Added database router. Allows TENANT_APPS and SHARED_APPS to be synced completely separately without messing with Django settings like INSTALLED_APPS or model.meta.managed. Centralized auth is now possible, but cross schema constraints will not be created. This also makes this app thread safe, fixes #2.
This commit is contained in:
parent
70dd4ad463
commit
eed14ccc3c
|
@ -21,6 +21,13 @@ Your ``DATABASE_ENGINE`` setting needs to be changed to
|
|||
# ..
|
||||
}
|
||||
}
|
||||
|
||||
Add `tenant_schemas.routers.TenantSyncRouter` to your `DATABASE_ROUTERS` setting, so that the correct apps can be synced, depending on what's being synced (shared or tenant).
|
||||
|
||||
DATABASE_ROUTERS = (
|
||||
'tenant_schemas.routers.TenantSyncRouter',
|
||||
)
|
||||
|
||||
|
||||
Add the middleware ``tenant_schemas.middleware.TenantMiddleware`` to the top of ``MIDDLEWARE_CLASSES``, so that each request can be set to use the correct schema.
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models import get_apps, get_models
|
||||
if "south" in settings.INSTALLED_APPS:
|
||||
from south.management.commands.syncdb import Command as SyncdbCommand
|
||||
|
@ -17,13 +18,14 @@ class Command(SyncCommon):
|
|||
def handle(self, *args, **options):
|
||||
super(Command, self).handle(*args, **options)
|
||||
|
||||
if 'tenant_schemas.routers.TenantSyncRouter' not in settings.DATABASE_ROUTERS:
|
||||
raise ImproperlyConfigured("DATABASE_ROUTERS setting must contain "
|
||||
"'tenant_schemas.routers.TenantSyncRouter'.")
|
||||
|
||||
if "south" in settings.INSTALLED_APPS:
|
||||
self.options["migrate"] = False
|
||||
|
||||
# save original settings
|
||||
for model in get_models(include_auto_created=True):
|
||||
setattr(model._meta, 'was_managed', model._meta.managed)
|
||||
|
||||
# Content types may be different on tenants, so reset the cache
|
||||
ContentType.objects.clear_cache()
|
||||
|
||||
if self.sync_public:
|
||||
|
@ -31,32 +33,12 @@ class Command(SyncCommon):
|
|||
if self.sync_tenant:
|
||||
self.sync_tenant_apps(self.schema_name)
|
||||
|
||||
# restore settings
|
||||
for model in get_models(include_auto_created=True):
|
||||
model._meta.managed = model._meta.was_managed
|
||||
|
||||
def _set_managed_apps(self, included_apps):
|
||||
""" sets which apps are managed by syncdb """
|
||||
for model in get_models(include_auto_created=True):
|
||||
model._meta.managed = False
|
||||
|
||||
verbosity = int(self.options.get('verbosity'))
|
||||
for app_model in get_apps():
|
||||
app_name = app_model.__name__.replace('.models', '')
|
||||
if app_name in included_apps:
|
||||
for model in get_models(app_model, include_auto_created=True):
|
||||
model._meta.managed = model._meta.was_managed
|
||||
if model._meta.managed and verbosity >= 3:
|
||||
self._notice("=== Include Model: %s: %s" % (app_name, model.__name__))
|
||||
|
||||
def _sync_tenant(self, tenant):
|
||||
self._notice("=== Running syncdb for schema: %s" % tenant.schema_name)
|
||||
connection.set_tenant(tenant, include_public=False)
|
||||
SyncdbCommand().execute(**self.options)
|
||||
|
||||
def sync_tenant_apps(self, schema_name=None):
|
||||
apps = self.tenant_apps or self.installed_apps
|
||||
self._set_managed_apps(apps)
|
||||
if schema_name:
|
||||
tenant = get_tenant_model().objects.filter(schema_name=schema_name).get()
|
||||
self._sync_tenant(tenant)
|
||||
|
@ -69,7 +51,5 @@ class Command(SyncCommon):
|
|||
self._sync_tenant(tenant)
|
||||
|
||||
def sync_public_apps(self):
|
||||
apps = self.shared_apps or self.installed_apps
|
||||
self._set_managed_apps(apps)
|
||||
SyncdbCommand().execute(**self.options)
|
||||
self._notice("=== Running syncdb for schema public")
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
from django.conf import settings
|
||||
|
||||
|
||||
class TenantSyncRouter(object):
|
||||
"""
|
||||
A router to control which applications will be synced,
|
||||
depending if we are syncing the shared apps or the tenant apps.
|
||||
"""
|
||||
|
||||
def allow_syncdb(self, db, model):
|
||||
# the imports below need to be done here else django <1.5 goes crazy
|
||||
# https://code.djangoproject.com/ticket/20704
|
||||
from django.db import connection
|
||||
from tenant_schemas.utils import get_public_schema_name, app_labels
|
||||
|
||||
if connection.schema_name == get_public_schema_name():
|
||||
if model._meta.app_label not in app_labels(settings.SHARED_APPS):
|
||||
return False
|
||||
else:
|
||||
if model._meta.app_label not in app_labels(settings.TENANT_APPS):
|
||||
return False
|
||||
|
||||
return None
|
|
@ -96,3 +96,10 @@ def schema_exists(schema_name):
|
|||
cursor.close()
|
||||
|
||||
return exists
|
||||
|
||||
|
||||
def app_labels(apps_list):
|
||||
"""
|
||||
Returns a list of app labels of the given apps_list
|
||||
"""
|
||||
return [app.split('.')[-1] for app in apps_list]
|
Loading…
Reference in New Issue