bernardopires / django-tenant-schemas Goto Github PK
View Code? Open in Web Editor NEWTenant support for Django using PostgreSQL schemas.
Home Page: https://django-tenant-schemas.readthedocs.org/en/latest/
License: MIT License
Tenant support for Django using PostgreSQL schemas.
Home Page: https://django-tenant-schemas.readthedocs.org/en/latest/
License: MIT License
With a fresh install of 1.3.1, some management commands are missing.
I discovered this when issuing a tenant_command:
(venv)vagrant@precise64:/vagrant/club_sites$ ./manage.py tenant_command createsuperuser --schema=club2
Unknown command: 'tenant_command'
Running manage.py help:
(venv)vagrant@precise64:/vagrant/club_sites$ ./manage.py help
...
[tenant_schemas]
migrate_schemas
sync_schemas
It's been awhile since I inspected tenant_schemas. I've been using a branch successfully in my SaaS. I wanted to check out the latest commit. In doing so, however, the latest software seems to not work with my requirements.
I require that django.contrib.auth exists in public, since I want centralized authorization and billing (my stripe-based billing app needs to join in with the auth_user table). However, it seems that the latest tenant_schema code requires that auth also be placed in TENANT_APPS (in addition to optionally in SHARED_APPS). Otherwise, I get a DB error when doing sync_schemas. However, when I do that and successfully do a sync_schemas, my users (for which there exists an auth table in public) are not authorized to login into a tenant. I suppose I would need to somehow synchronize the user in each tenant with auth_user in public. But that would be too unwieldy.
I would like to use the latest commit. With my current branch of tenant_schemas (forked 9 months ago), whenever I do a syncdb, I need to delete tables in public that should only be in each tenant. Your latest commit seems to have a solution for that using sync_db.
Any thoughts?
I had everything working this morning then I updated to the pypi 1.0 version and ran into an error with the database engine:
(tenants)mike@ellie ~/sites/tenants $ ./manage.py validate
ImproperlyConfigured: 'tenant_schemas.postgresql_backend' isn't an available database backend.
Try using 'django.db.backends.XXX', where XXX is one of:
u'mysql', u'oracle', u'postgresql_psycopg2', u'sqlite3'
Error was: No module named postgresql_backend.base
If you have common apps which are either in SHARED_APPS and TENANT_APP, adding them will cause appearing the same app twice in INSTALLED_APPS. I don't know Django enough and can't see if this can cause trouble.
I would like to enable support for django.contrib.sites for tenants. To do this I propose adding an extra model. I propose we call the model ClientSite and have a ForeignKey relationship to Client (or the abstract model it inherits from). What do you reckon? Does this sound feasible?
I am trying to install version 1.4.0 of django-tenant-schemas, but it fails. Here's pip output:
(venv)ottavio@magritte:~/Projects/Miei/webcapm$ pip install django-tenant-schemas
Downloading/unpacking django-tenant-schemas
Running setup.py egg_info for package django-tenant-schemas
error: package directory 'examples' does not exist
Complete output from command python setup.py egg_info:
running egg_info
writing requirements to pip-egg-info/django_tenant_schemas.egg-info/requires.txt
writing pip-egg-info/django_tenant_schemas.egg-info/PKG-INFO
writing top-level names to pip-egg-info/django_tenant_schemas.egg-info/top_level.txt
writing dependency_links to pip-egg-info/django_tenant_schemas.egg-info/dependency_links.txt
warning: manifest_maker: standard file '-c' not found
error: package directory 'examples' does not exist
----------------------------------------
Command python setup.py egg_info failed with error code 1 in /home/ottavio/Projects/Miei/webcapm/venv/build/django-tenant-schemas
Storing complete log in /home/ottavio/.pip/pip.log
(venv)ottavio@magritte:~/Projects/Miei/webcapm$
in pip.log I have this additional information
Command python setup.py egg_info failed with error code 1 in /home/ottavio/Projects/Miei/webcapm/venv/build/django-tenant-schemas
Exception information:
Traceback (most recent call last):
File "/home/ottavio/Projects/Miei/webcapm/venv/local/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/basecommand.py", line 104, in main
status = self.run(options, args)
File "/home/ottavio/Projects/Miei/webcapm/venv/local/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/commands/install.py", line 245, in run
requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle)
File "/home/ottavio/Projects/Miei/webcapm/venv/local/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/req.py", line 1009, in prepare_files
req_to_install.run_egg_info()
File "/home/ottavio/Projects/Miei/webcapm/venv/local/lib/python2.7/site-packages/pip-1.1-py2.7.egg/pip/req.py", line 225, in run_egg_info
It`s possible to use for different DB, not for schema in postgre?
Bernardo -
This is not an issue perse, but more a question about communications about this project. What you are doing is very important for SaaS apps, and I have forked the code and started to explore it for my own SaaS development. There does not seem to be a place for communications on django-tenant-schemas, like a forum. Has there been one set up? I think some sort of forum could really generate a lot of interest and positive contributions.
I'm interested in using the code, but would like to get it to work with Django's built-in authorization/authentication. I've looked at Django simple multi-tenant and this blog: http://www.loggly.com/blog/2009/12/django-middleware-munging/ , so I think with a little effort, we can get some good authorization/authentication supported leveraging existing stuff.
Also, it would be great to use it with Django contrib.admin. With the current setup using your public token, the code will need some small work to enable that.
Thanks,
Ted ([email protected])
Hi ! again.
My config : ubuntu server 12.04LTS clean install , postgresql 9.2 , django 1.5.1
when I perform : python manage.py sync_schemas --shared , script runs ok but suddenly breaks , output:
/usr/local/lib/python2.7/dist-packages/tenant_schemas/postgresql_backend/base.py:59: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
raise utils.DatabaseError(e.message)
anybody knows why?
Please take a look at tenant_schemas/tests/schemas.py and search for the string todo
.
It'd be great if there were documented somewhere (just in here for a start) the best way to set up a server deployment of a project, particularly on Apache.
For example, I've set up 'A record' routing with my domain hosting provider to route all traffic with '*' wildcard prefix, and with no prefix, to my server.
1st question, how best to handle www.mydomain.com so that it hits the public schema and doesn't try for a tenant url of 'www'. Is that a rewrite rule?
And more importantly, how best to setup the Apache config? I think it's with Virtual Hosts, and based off Bernardo's comment in #9 (comment) this can be wildcarded too.
Apache admin isn't a strength of mine, so while I'm confident I could get it working, this will be something that most everyone will need to do with this framework and some solid advice would be appreciated.
Thanks!
Hi - Great package! It's really clean and easy to use so far. As I'm playing with it, I'm having some trouble getting the Admin stuff to work. I'm trying to setup Admin on the main tenant, but having some trouble with tenant-schemas attaching /main/ to the url. Also, the main admin be able to view data in the other schemas, or am I supposed to setup a superuser for each new tenant?
Dear bcarneiro
I really appreciate your masterpiece.
Dear All.
My Plan to use django-tenant-schema is to manage B2B relation, communication, transaction between tenants.
MyApproach is that the only Tenant-Specific will the standard auth-*
All other part will Shared-app.
This way I will need to flag each record on public model with tenant ID of loged-in user,
i.e, based on https://github.com/bcarneiro/django-tenant-schemas:
Let's say I want tenant will able to rent each other cars ... so 'car' will be in public app with :
class Car(models.Model):
client = models.ForeignKey(Client)
badge = models.CharField(max_length=10, blank=False, unique=True)
My Quetion is :
Kindly please give me any your enlightment
Sincerely
-bino-
Hi everybody!
This project is cool! , but I have some troubles for now. When I do "python manage.py sync_schemas" my server responses "Unknown command: 'sync_schemas'" anybody has the same problem?
In my manage.py available subcommands doesn't appear sync_schemas , and my settings.py Is correctly like information in readthedocs(Last).
I appreciate your comments! , good luck
Hi!
How I can access to schema to save in the auth_user of my app a new user, when I create a new tenant?
Thanks
sync_schemas should not sync apps managed by south
My particular use-case may be on the edge, but I have a situation where I need the dynamic schema selection to occur on two or more domain names. For example, subdomain1.example.com and subdomain2.example.net could both use the same postgres schema. The solution I implemented was to:
One could implement the domain_aliases as an external table, but it seems like this simpler approach would work, and saves an additional relationship. I suppose my solution could be reduced to a single database call by using filter() once instead of get() twice, but the result would be less precise.
At any rate, I pushed this change into production these evening and it works great.
Would anyone like to see the code? Or receive a pull request?
I get these warning from setup.py :
Running setup.py egg_info for package django-tenant-schemas
warning: no files found matching 'LICENSE'
warning: no files found matching 'version.py'
warning: no files found matching 'VERSION'
When splitting apps up into "shared" and "tenant" apps, running unit tests doesn't function as expected. I found the following:
This is all pretty confusing to me...any thoughts on what's going on would be greatly appreciated! Would be happy to write a patch if I knew what was happening.
Thanks.
First, thanks for this project. Although I am not using it since I don't use postgres, I found it helpful when researching multi-tenancy options.
I believe I have the answer to one mystery noted in the middleware. There, each request gratuitously issues connection.set_schema_to_public()
first, soon followed by connection.set_tenant(..)
.
When using devserver, which is multithreaded by default (unless --nothreading
is specified), I noticed a single thread only ever services a single connection
object, ie, a new thread is spawned per request, and is discarded at the end of the request.
However, other servers such as gunicorn keep worker pools, meaning a long-lived thread will service distinct connection
objects throughout its lifetime.
Since Django closes connections at the end of the request (look for signals.request_finished
in django.db.__init__
), it means the connection state is effectively reset after a request -- even though the threadlocal data persists. Thus the threadlocal data (applied search paths) is out-of-sync with the true connection state (default for new connection).
In summary, I believe you should attach some thread local state to the connection, not just to the thread. Since connections are threadlocal in django unless allow_thread_sharing
is set, it'd probably be safe to just set/test an attribute the connection (ie cursor.connection.applied_tenant = tenant
). (In fact, it shouldn't matter if the connection is shared or not, since the applied search path is connection state regardless).
This should also help you avoid spurious SET
calls when the tenant has already been set on a given connection.
Hope this helps!
Hello,
Thank you for writing this app - it is fantastic - exactly what I am in need of.
I am having a bit of difficulty getting integration with South working. I have followed your simple tutorial at https://django-tenant-schemas.readthedocs.org/en/latest/use.html - after setting everything up as stated in https://django-tenant-schemas.readthedocs.org/en/latest/install.html.
However, I am still confused with how I can use South and this app. I see the commands in the tutorial but cannot figure out the order in which I run them.
For example, I wish to add an additional field, 'additional_field', to the Client model. I add in the field, then I run ./manage.py migrate. But I receive a DatabaseError:
DatabaseError: column customers_client.additional_field does not exist
LINE 1: ...ent"."paid_until", "customers_client"."on_trial", "customers...
Am I missing something? Can someone provide a simple example as to how this can be rectified?
Many thanks.
migrate_schemas should respect SHARED_APPS and TENANT_APPS
Dear Bernardo and All
I Read and do all as mentioned at https://github.com/bcarneiro/django-tenant-schemas/blob/master/README.markdown , but still got no luck
my pastebin for :
my project name is 'mts1'
Whenever I make request to http://bino.int:8000/login , or http://cl1.bino.int:8000/login ..
I got exception , traceback at --> http://pastebin.com/0T0uGvdc
additionaly, I also read about create superuser at #24 , and I still don't know where is the BaseTenantCommand.
Kindly please give your enlighten to fix the problem
Sincerely
-bino-
Thanks for the good work! This will be a very useful project.
I've been trying out tenant-schemas, but have some questions about compatibility with existing django apps. I know it's impossible to say without auditing a particular app, but it would be nice to have a place in the wiki for known apps, issues, and possible workarounds.
Specifically I'm looking at django-guardian, with auth/users as a tenant app. From a brief code review, I don't see anything that would keep it from being used as a tenant app and it seems to be working in my test project. Good so far, but better to see experience of others to put my mind at ease!
Also, it would be nice to mention or include a caching backend that allows for separating tenant caches easily. I would assume cache collisions to be the biggest issue with 3rd party apps. Something simple like
class TenantMemcachedCache(MemcachedCache):
def make_key(self, key, version=None):
tenant = connection.get_tenant()
return force_str(super(TenantMemcachedCache, self).make_key('%s-%s' % (tenant,key), version))
That wouldn't fix code level caching like ContribTypes, but hopefully those instances are rare.
Hi,
Do you intend to porting the app to Python 3?
I have a Python 3 / Django 1.6 project and I decided to use your app. As I didn't find Python 3 port, I did it myself.
I only had to run: 2to3 -w django-tenant-schemas
Then, I changed setup.py:
from .version import get_git_version
to
from version import get_git_version
And version.py (get_git_version function):
return version[1:]
to
return str(version[1:]
And that was it! I'm using it without problems so far (at least I don't get errors caused by the port)
I suppose it won't be so much of a work to port to Python 3.
Alex
There is a check if current schema is public in models.py:
http://github.com/bcarneiro/django-tenant-schemas/blob/master/tenant_schemas/models.py#L30
I wonder what is the purpose of this check?
Is it safe to simply:
if connection.get_schema() != get_public_schema_name():
connection.set_schema_to_public()
The problem is when I create a new tenant from shell, it always set the same to the schema for that Tenant, but doesn't change it back, so I cannot create a new Tenant from that shell session. Is it ok to simply set schema to public?
The error message:
migrate has been disabled, use migrates_schemas instead...
Should read:
migrate has been disabled, use migrate_schemas instead...
This is being used right now in production on a small project and I have made an attempt to make it thread-safe, but I'm a complete beginner at this subject. Any help on this would be HIGHLY appreciated. Can someone please check if the custom postgresql_backend
is thread-safe? If there is a way to write a test for this, it would be awesome.
For any reason, the post_delete signal is not being called.
I will take a look tomorrow if I have a moment.
The schema is created and synchronized correctly, but after that, the following error occurs:
'NoneType' object has no attribute 'schema_name'
Traceback (most recent call last):
File "/home/jjimenez/venv/my_project/local/lib/python2.7/site->packages/jsonview/decorators.py", line 42, in _wrapped
ret = f(request, _a, *_kw)
File "/home/jjimenez/Work/my_project/src/my_project/customers/views.py", line 67, in save_quick_customer
customer.save(admin_email=admin_email)
File "/home/jjimenez/Work/my_project/src/my_project/customers/models.py", line 62, in save
admin_user.save()
File "/usr/lib/python2.7/contextlib.py", line 24, in exit
self.gen.next()
File "/home/jjimenez/venv/my_project/local/lib/python2.7/site->packages/django_tenant_schemas-1.3.1_12_g6899a7d->py2.7.egg/tenant_schemas/utils.py", line 25, in tenant_context
connection.set_tenant(previous_tenant)
File "/home/jjimenez/venv/my_project/local/lib/python2.7/site->packages/django_tenant_schemas-1.3.1_12_g6899a7d->py2.7.egg/tenant_schemas/postgresql_backend/base.py", line 107, in set_tenant
self.set_settings_schema(tenant.schema_name)
AttributeError: 'NoneType' object has no attribute 'schema_name'
Hey,
Firstly I would like to say very good work, I spent so long trying to make multi-tenancy work in a number of different ways over the last year and this app was absolutely seamless, you are absolutely amazing!
Just a quick one from me, do you know how I might clone data from the default schema to the tenant schema? Is there a command to change which schema you are currently using? I'll explain the problem briefly, I have django.contrib.auth as both a tenant app and a shared app. I would like to copy over the user that created the Client (therefore the schema) to the tenant django.contrib.auth as a superuser.
Also, I would like to help out in any way that I can, I figure a good way to start would be to get the docs into sphinx format and write some more, if I do this and submit a pull request would you be willing to setup http://readthedocs.com and set it to pull from this repo? Would this be helpful?
All the best,
Chris
$ pip install -e '[email protected]:bcarneiro/django-tenant-schemas.git@master#egg=django_tenant_schemas-dev'
yields:
Obtaining django-tenant-schemas from git+git@github.com:bcarneiro/django-tenant-schemas.git@master#egg=django_tenant_schemas-dev
Updating /home/steve/virtualenvs/testcase/src/django-tenant-schemas clone (to master)
Running setup.py egg_info for package django-tenant-schemas
Traceback (most recent call last):
File "<string>", line 16, in <module>
File "/home/steve/virtualenvs/testcase/src/django-tenant-schemas/setup.py", line 10, in <module>
from tenant_schemas import __version__
File "tenant_schemas/__init__.py", line 3, in <module>
from django.db.models.signals import post_delete
File "/home/steve/virtualenvs/testcase/local/lib/python2.7/site-packages/django/db/__init__.py", line 11, in <module>
if settings.DATABASES and DEFAULT_DB_ALIAS not in settings.DATABASES:
File "/home/steve/virtualenvs/testcase/local/lib/python2.7/site-packages/django/conf/__init__.py", line 53, in __getattr__
self._setup(name)
File "/home/steve/virtualenvs/testcase/local/lib/python2.7/site-packages/django/conf/__init__.py", line 46, in _setup
% (desc, ENVIRONMENT_VARIABLE))
django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 16, in <module>
File "/home/steve/virtualenvs/testcase/src/django-tenant-schemas/setup.py", line 10, in <module>
from tenant_schemas import __version__
File "tenant_schemas/__init__.py", line 3, in <module>
from django.db.models.signals import post_delete
File "/home/steve/virtualenvs/testcase/local/lib/python2.7/site-packages/django/db/__init__.py", line 11, in <module>
if settings.DATABASES and DEFAULT_DB_ALIAS not in settings.DATABASES:
File "/home/steve/virtualenvs/testcase/local/lib/python2.7/site-packages/django/conf/__init__.py", line 53, in __getattr__
self._setup(name)
File "/home/steve/virtualenvs/testcase/local/lib/python2.7/site-packages/django/conf/__init__.py", line 46, in _setup
% (desc, ENVIRONMENT_VARIABLE))
django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
A little googling reveals how the folks over at django-tracking worked around this issue:
https://bitbucket.org/codekoala/django-tracking/commits/f365cd2d59ef
I tried that approach and still had some problems, but I did notice that commenting out everything in tenant_schemas/__init__.py
except the version number allows the install to complete.
That said, I do not like the django-tracking approach... it doesn't seem very pythonic. It's just a workaround to let you do things in places where you're apparently not supposed to do them.
Anyone have any thoughts?
I create my Shared schema initially:
bin/django sync_schemas --shared
bin/django migrate_schemas
...
from management.models import Client
tenant = Client(domain_url='localhost',
schema_name='public',
name='Schemas Inc.',
on_trial=False)
tenant.save()
Then create a tenant:
from management.models import Client
tenant = Client(domain_url='tenant1.localhost',
schema_name='tenant1',
name='The Tenant1 Inc.',
on_trial=False)
tenant.save()
This causes the middleware to create the new schema. But for my tenant-only app (fids_admin), the tables don't get created. Reason being the South migrations are faked:
=== Running migrate for schema: tenant1
Running migrations for fids_admin:
- Migrating forwards to 0002_auto__add_field_flight_recurrences.
> fids_admin:0001_initial
(faked)
> fids_admin:0002_auto__add_field_flight_recurrences
(faked)
To work around this I delete all rows from tenantschema.south_migrationhistory then run:
bin/django migrate_schemas
Here's my apps config in settings:
SHARED_APPS = (
'tenant_schemas', # mandatory
# everything below here is optional
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.admin',
'django.contrib.staticfiles',
'south',
'management',
)
TENANT_APPS = (
# The following Django contrib apps must be in TENANT_APPS
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.staticfiles',
'south',
# your tenant-specific apps
'fids_admin',
'recurrence',
)
Why would the tenant creation fake the migration steps?
tenant-schemas v1.3.1
South v0.7.6
Thanks
Could you please elaborate on the tenant url routing portion as well?
If you go through https://github.com/tkaemming/django-subdomains/blob/master/docs/index.rst they have given ample instructions as how to set their urls.
I am finding it difficult to set up the subdomains following the docs as is.
If you could supplement with an example, it will be great.
Thanks!
Hi,
I haven't installed the multi-tenant package yet. I think perhaps it doesn't meet my requirements. If I understand correctly, the TENANT_APPS' tables are created in each of the tenant schemas. So, if I want to run a query that spans all of the data in all the schemas I would have to do a union, correct?
I had an idea. One thing you can do in postgres is inherit a table. So, for example, I can create my table in the public schema, then, when I want that same table for a tenant I could:
When the tenant table is separate, data inserted into that table cannot be accessed by another tenant. However, all data entered in a tenant schemas can be selected in the central 'public.mytable' table. Another neat side effect is when south updates the public table the tenant tables automatically. I tried this a bit, I am going to do some more work with this. What do you think about this approach?
---greg
An application is considered to be shared when it's table are in the public
schema. Some apps make sense being shared. Suppose you have some sort of public data set, for example, a table containing census data. You want every tenant to be able to query it.
Right now, this is not possible, at least not in practical way. By default all models are being synced to every schema, including public
. Please take a look at the tenant-schemas needs your help! section if you have an idea on how to do this.
django-appschema
tries to solve this in a very hackish and dangerous way by altering django's app cache. This is not safe for on-the-fly creation of tenants, so this is not an option. django-schemata partially solves it by forcing you to move your shared tables to the public
schema. When syncing the tables for tenant-specific applications, the search path is set to public
plus the tenant's schema, which means all tables that already exist on public
will not be created when syncing. This is not ideal because it doesn't allow you have to applications that are both shared and tenant-specific. For example, you may need to have a user system for your main domain and another for your tenants. Or you may want to have south
in both.
To enable this, an idea would be to let all models, both shared and tenant-specific to be synced. After the sync, the unnecessary models can be deleted from the database. There would be three arrays, SHARED_APPS
, TENANT_APPS
and MUTUAL_APPS
. For example, when syncing the public
schema, we can just iterate over TENANT_APPS
deleting their tables. When syncing tenants, we delete the SHARED_APPS
tables. We can then enable the tenants to also see the public
schema. This is of course not very elegant, but shouldn't present a big hit on performance (how often do you sync your models?) and doesn't involve hacking django's cache.
An ever simpler solution would be if it were possible to select which models have to be synced. AFAIK this is not possible, syncdb is called for all models on INSTALLED_APPS
.
What do you think of this solution? Do you have a better idea? Please send in your feedback!
The way I use this app is this:
class Team(Site, TenantMixin):
site = models.OneToOneField(Site, parent_link=True)
The problem is, that the built in django Site
model already has a domain
field, so when I do this, I got domain_url
and domain
fields on the Team model, which is redundant and broke DRY principle.
By renaming domain_url
field to domain
, the integration with sites framework would became seamless.
I also propose changing schema_name
change to schema
as that is ugly, unnecesary and I hate typing that much :) Also I think schema
describe more precisely the purpose of this field.
With all these changes and the new shared feature we could make a new v.2.0 release, indicating the API breaking changes.
What you think about this @bernardopires?
Running into a problem when attempting to initially sync schemas. Keep getting error: Unknown command: 'sync_schemas'.. I've attempted to install django-tenant-schemas a few times through pip to no avail.
I don't believe all the folders are being synced correctly using pip. In fact, I believe I'm missing all of them, along with the management folder that houses all the commands... That would be the problem. heh
Basically 100% of the code was copied from Django's source, just to be able to remove settings.TENANT_URL_TOKEN
from the URL. There should be a smarter way to do this.
Hi there. So far I'm not able to get this app working for me. I'm mostly following the documentation here with a few organizational tweaks of my own (nothing major).
I'm running into a DatabaseError when I try to save a new (non-public) Client record:
django.db.utils.DatabaseError
DatabaseError: relation "django_content_type" does not exist
LINE 1: ..."."app_label", "django_content_type"."model" FROM "django_co...
Seems as though the tenant schemas aren't being properly related back to the public schema for access to django_content_type records.
Here's the code for my implementation, and here's full detail on the error I'm receiving when I try to save a new Client.
ImportError: No module named six.moves
when trying to create tenants. We need to either find a solution or only support Django 1.5+
Running
python manage.py test tenant_schemas
returns the following results:
=====================================================================
ERROR: test_edit_tenant (tenant_schemas.tests.tenants.TenantTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/var/virtual/test/local/lib/python2.7/site-packages/tenant_schemas/tests
/tenants.py", line 53, in test_edit_tenant
tenant.save()
File "/var/virtual/test/local/lib/python2.7/site-packages/tenant_schemas/model
s.py", line 23, in save
raise Exception("Can't update tenant outside the public schema. Current sche
ma is %s." % connection.get_schema())
Exception: Can't update tenant outside the public schema. Current schema is test
.
======================================================================
FAIL: test_switching_search_path (tenant_schemas.tests.tenants.TenantTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/var/virtual/test/local/lib/python2.7/site-packages/tenant_schemas/tests
/tenants.py", line 96, in test_switching_search_path
self.assertEqual(DummyModel.objects.count(), dummies_tenant1_count)
AssertionError: 5 != 2
----------------------------------------------------------------------
Ran 6 tests in 1.038s
FAILED (failures=1, errors=1)
Destroying test database for alias 'default'...
The actual client/tenant application used was the example project that I grabbed from
caioariede@943becd
Using the above example project, my settings are
SHARED_APPS = (
'tenant_schemas',
'customers',
)
TENANT_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'example_project',
)
INSTALLED_APPS = SHARED_APPS + TENANT_APPS
TENANT_MODEL = "customers.Client"
Additional details:
Postgres 9.1 on Ubuntu 12.04 LTS x86
Django==1.5.1
django-tenant-schemas==1.1.3
psycopg2==2.5
Expected results: all tests should pass
Hi,
Did you consider using the sites framework for the tenants?
If possible then I think it would create a "cleaner" solution and play nice with other packages that use that framework.
Regards,
-Stefan
Hi Bernardo
Some comments to aid the install docs, no issue here yet:).
Running under buildout requires:
unzip = true
Otherwise the extra django commands cannot be found by the buildout-generated bin/django script.
A dependency that needs to be included is: psycopg2
The docs suggest that SHARED_APPS and TENANT_APPS are optional, but they seem to be required?
I'll keep my experience notes coming in here if this is the best place?
Thanks, and look forward to running it for the first time soon!
Brad
Hi
after getting the latest version, starting my project results in this error:
File "/var/www/simulator-build/activeliner/models/init.py", line 4, in
from client import Client
File "/var/www/simulator-build/activeliner/models/client.py", line 6, in
from tenant_schemas.models import TenantMixin
File "/srv/environments/simulator-build/local/lib/python2.7/site-packages/tenant_schemas/models.py", line 5, in
from tenant_schemas.signals import post_schema_sync
ImportError: No module named signals
I cannot find signals.py or a signals directory here, so I'm guessing some files have gone missing. Is that so?
And in other news, thank you for this great project!
I was thinking about this for quite some time, but now in connection with #43 I could finally draft this idea:
Get rid of PUBLIC_SCHEMA_URLCONF setting, and in the documentation, suggest a solution with a different wsgi_app for the public website which point to a different settings.py (settings_public).
# wsgi_main_website.py
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings_public")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
This would need to set up a new wsgi instance, but I don't think that's a problem and this would have the following benefits:
ContentType.objects.clear_cache()
from the middleware, because this case, every schema would have the same app in contenttypes in the same place.auth
and admin
both on public and on tenant?"public
schema for the public website only and tenant apps without referencing public?I will do it myself for sure, because I think overall this is the right way to do it but would be nice to get some comments on this one, and I think others could benefit from this also.
Hi!
My settings :
SHARED_APPS=(
'tenant_schemas',
'South',
.
.
.
'Tariff',
)
TENANT_APPS=(
'Core',# Core has a class with a attribute with foreingkey with newapp
'South',
)
When I perform :
$ python manage.py sync_schemas
the tenant schema that has name demo
=== Running syncdb for schema demo
Syncing...
Creating tables ...
Creating table Core_metering_element_data
Creating table Core_metering_element_tariff
DatabaseError: relation "Tariff_company_tariff" does not exist
Anybody knows why I can update my schemas?
I tried a south datamigration which calls call_command("loaddata", "default_cities.json")
and this works fine for tables that need migrating. But when creating a new tenant (read: schema) from scratch, of course it doesn't get run (South thinks nothing to migrate) so the data doesn't get populated.
I can run loaddata directly, but this would have to be done manually for each tenant addition
Any advice?
Cheers
Hi, First of all I appreciate such a useful and great project. I will like to send you a link to a test project (minimal Blog) I've put that can be useful for people interested in starting using your code.
Second: Are you willing to include a management command to create superusers in the schemas ? I think that can be useful in settings such as the one of blogs that use admin to enter data. In affirmative case I can put some time to contribute it.
regards,
Hey,
Sorry to bother you, getting this error now with the latest version from pip:
Environment:
Request Method: GET
Request URL: http://localhost:8000/admin/
Django Version: 1.4.5
Python Version: 2.7.3
Installed Applications:
('tenant_schemas',
'tart.core.accounts',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.admin',
'tart.core.main_app',
'tart.contrib.facebookext',
'helpdesk',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.admin',
'tart.contrib.facebookext',
'helpdesk',
'cms',
'mptt',
'menus',
'sekizai',
'cms.plugins.file',
'cms.plugins.picture',
'cms.plugins.teaser',
'cms.plugins.video',
'cms.plugins.flash',
'cms.plugins.googlemap',
'cms.plugins.link',
'cms.plugins.text',
'cms.plugins.twitter')
Installed Middleware:
('tenant_schemas.middleware.TenantMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.doc.XViewMiddleware',
'django.middleware.common.CommonMiddleware',
'cms.middleware.page.CurrentPageMiddleware',
'cms.middleware.user.CurrentUserMiddleware',
'cms.middleware.toolbar.ToolbarMiddleware',
'tart.core.main_app.middleware.ListSitesMiddleware')
Traceback:
File "/home/chris/.virtualenvs/tartng/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
89. response = middleware_method(request)
File "/home/chris/.virtualenvs/tartng/local/lib/python2.7/site-packages/tenant_schemas/middleware.py" in process_request
26. connection.set_schema_to_public()
File "/home/chris/.virtualenvs/tartng/local/lib/python2.7/site-packages/django/db/__init__.py" in __getattr__
34. return getattr(connections[DEFAULT_DB_ALIAS], item)
Exception Type: AttributeError at /admin/
Exception Value: 'DatabaseWrapper' object has no attribute 'set_schema_to_public'
settings.py
DATABASES = {
'default': {
'ENGINE': 'tenant_schemas.postgresql_backend',
'NAME': 'dbname',
'USER': 'user',
'PASSWORD': 'REDACTED',
'HOST': 'localhost',
'PORT': '',
}
}
MIDDLEWARE_CLASSES = (
'tenant_schemas.middleware.TenantMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.doc.XViewMiddleware',
'django.middleware.common.CommonMiddleware',
'cms.middleware.page.CurrentPageMiddleware',
'cms.middleware.user.CurrentUserMiddleware',
'cms.middleware.toolbar.ToolbarMiddleware',
'tart.core.main_app.middleware.ListSitesMiddleware'
)
DJANGO_CMS_APPS = (
# These are all for django-cms
'cms', # django CMS itself
'mptt', # utilities for implementing a modified pre-order traversal tree
'menus', # helper for model independent hierarchical website navigation
'sekizai', # for javascript and css management
# These are plugins for django-cms
#'cms_themes',
# 'filer',
# 'cmsplugin_filer_file',
# 'cmsplugin_filer_folder',
# 'cmsplugin_filer_image',
# 'cmsplugin_filer_teaser',
# 'cmsplugin_filer_video',
'cms.plugins.file',
'cms.plugins.picture',
'cms.plugins.teaser',
'cms.plugins.video',
'cms.plugins.flash',
'cms.plugins.googlemap',
'cms.plugins.link',
#'cms.plugins.snippet', # Potential security hazard, see Snippet in django-cms docs
'cms.plugins.text',
'cms.plugins.twitter',
)
SHARED_APPS = (
'tenant_schemas', # mandatory
'tart.core.accounts', # you must list the app where your tenant model resides in
# everything below here is optional
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.admin',
'tart.core.main_app', # Main application
'tart.contrib.facebookext', # Facebook extensions
'helpdesk', # helpdesk with email support
)
TENANT_APPS = (
# The following Django contrib apps must be in TENANT_APPS
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.admin',
'tart.contrib.facebookext', # Facebook extensions
'helpdesk', # helpdesk with email support
) + DJANGO_CMS_APPS
INSTALLED_APPS = SHARED_APPS + TENANT_APPS
TENANT_MODEL = "tart.core.accounts.Client" # app.Model
SOUTH_DATABASE_ADAPTERS = {
'default': 'south.db.postgresql_psycopg2',
}
This is the contents of TENANT_MODEL (tart.core.accounts.client):
from django.db import models
from django.contrib.auth.models import User
from django.contrib import admin
from django import forms
import datetime
import os
class Base(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now_add=True, auto_now=True)
class Meta:
abstract = True
from tenant_schemas.models import TenantMixin
from django.contrib.auth.models import User
class Client(TenantMixin, Base):
name = models.CharField(max_length=100)
paid_until = models.DateField()
PLANS = (
('Free', 'Personal Plan'),
('Pro', 'Professional Plan'),
('Heavy', 'Heavy User Plan'),
('WhtLbl', 'White Labelled'),
)
plan = models.CharField(max_length=6,
choices=PLANS,
default='Free')
user = models.ForeignKey(User, blank=True, null=True)
on_trial = models.BooleanField(default=True)
# default true, schema will be automatically created and synced when it is saved
auto_create_schema = True
This is the output of sync_schemas --shared:
python manage.py sync_schemas --shared
=== Running syncdb for schema public
Creating tables ...
Installing custom SQL ...
Installing indexes ...
Installed 80 object(s) from 1 fixture(s)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.