Пример #1
0
    def save(self, verbosity=1, *args, **kwargs):
        is_new = self.pk is None

        if is_new and connection.schema_name != get_public_schema_name():
            raise Exception("Can't create tenant outside the public schema. "
                            "Current schema is %s." % connection.schema_name)
        elif not is_new and connection.schema_name not in (
                self.schema_name, get_public_schema_name()):
            raise Exception("Can't update tenant outside it's own schema or "
                            "the public schema. Current schema is %s." %
                            connection.schema_name)

        super(TenantMixin, self).save(*args, **kwargs)

        if is_new and self.auto_create_schema:
            try:
                self.create_schema(check_if_exists=True, verbosity=verbosity)
            except:
                # We failed creating the tenant, delete what we created and
                # re-raise the exception
                connection.set_schema_to_public()
                self.delete(force_drop=True)
                raise
            else:
                post_schema_sync.send(sender=TenantMixin, tenant=self)
Пример #2
0
    def process_request(self, request):
        # Connection needs first to be at the public schema, as this is where
        # the tenant metadata is stored.
        connection.set_schema_to_public()
        hostname = self.hostname_from_request(request)

        TenantModel = get_tenant_model()
        try:
            request.tenant = TenantModel.objects.get(domain_url=hostname)
            connection.set_tenant(request.tenant)
        except TenantModel.DoesNotExist:
            raise self.TENANT_NOT_FOUND_EXCEPTION(
                'No tenant for hostname "%s"' % hostname)

        # Content type can no longer be cached as public and tenant schemas
        # have different models. If someone wants to change this, the cache
        # needs to be separated between public and shared schemas. If this
        # cache isn't cleared, this can cause permission problems. For example,
        # on public, a particular model has id 14, but on the tenants it has
        # the id 15. if 14 is cached instead of 15, the permissions for the
        # wrong model will be fetched.
        ContentType.objects.clear_cache()

        # Do we have a public-specific urlconf?
        if hasattr(
                settings, 'PUBLIC_SCHEMA_URLCONF'
        ) and request.tenant.schema_name == get_public_schema_name():
            request.urlconf = settings.PUBLIC_SCHEMA_URLCONF
Пример #3
0
    def handle(self, *args, **options):
        self.sync_tenant = options.get('tenant')
        self.sync_public = options.get('shared')
        self.schema_name = options.get('schema_name')
        self.installed_apps = settings.INSTALLED_APPS
        self.args = args
        self.options = options

        if self.schema_name:
            if self.sync_public:
                raise CommandError(
                    "schema should only be used with the --tenant switch.")
            elif self.schema_name == get_public_schema_name():
                self.sync_public = True
            else:
                self.sync_tenant = True
        elif not self.sync_public and not self.sync_tenant:
            # no options set, sync both
            self.sync_tenant = True
            self.sync_public = True

        if hasattr(settings, 'TENANT_APPS'):
            self.tenant_apps = settings.TENANT_APPS
        if hasattr(settings, 'SHARED_APPS'):
            self.shared_apps = settings.SHARED_APPS
Пример #4
0
    def handle(self, *args, **options):
        super(Command, self).handle(*args, **options)
        self.PUBLIC_SCHEMA_NAME = get_public_schema_name()

        if self.sync_public and not self.schema_name:
            self.schema_name = self.PUBLIC_SCHEMA_NAME

        if self.sync_public:
            self.run_migrations(self.schema_name, settings.SHARED_APPS)
        if self.sync_tenant:
            if self.schema_name and self.schema_name != self.PUBLIC_SCHEMA_NAME:
                if not schema_exists(self.schema_name):
                    raise RuntimeError('Schema "{}" does not exist'.format(
                        self.schema_name))
                else:
                    self.run_migrations(self.schema_name, settings.TENANT_APPS)
            else:
                all_tenants = get_tenant_model().objects.exclude(
                    schema_name=get_public_schema_name())
                for tenant in all_tenants:
                    self.run_migrations(tenant.schema_name,
                                        settings.TENANT_APPS)
Пример #5
0
    def process_request(self, request):
        try:
            super(TenantMiddleware, self).process_request(request)
        except self.TENANT_NOT_FOUND_EXCEPTION:

            connection.set_schema_to_public()
            schema_name = request.META.get('HTTP_DOMAIN',
                                           request.COOKIES.get('domain', None))
            schema_name = schema_name or get_public_schema_name()
            TenantModel = get_tenant_model()
            try:
                request.tenant = TenantModel.objects.get(
                    schema_name=schema_name)
                connection.set_tenant(request.tenant)
            except TenantModel.DoesNotExist:
                raise self.TENANT_NOT_FOUND_EXCEPTION(
                    'No tenant for domain"%s"' % schema_name)

            ContentType.objects.clear_cache()
            if hasattr(
                    settings, 'PUBLIC_SCHEMA_URLCONF'
            ) and request.tenant.schema_name == get_public_schema_name():
                request.urlconf = settings.PUBLIC_SCHEMA_URLCONF
Пример #6
0
    def delete(self, force_drop=False, *args, **kwargs):
        """
        Deletes this row. Drops the tenant's schema if the attribute
        auto_drop_schema set to True.
        """
        if connection.schema_name not in (self.schema_name,
                                          get_public_schema_name()):
            raise Exception("Can't delete tenant outside it's own schema or "
                            "the public schema. Current schema is %s." %
                            connection.schema_name)

        if schema_exists(self.schema_name) and (self.auto_drop_schema
                                                or force_drop):
            self.delete_schema()

        super(TenantMixin, self).delete(*args, **kwargs)
Пример #7
0
 def handle(self, *args, **options):
     """
     Iterates a command over all registered schemata.
     """
     if options['schema_name']:
         # only run on a particular schema
         connection.set_schema_to_public()
         self.execute_command(
             get_tenant_model().objects.get(
                 schema_name=options['schema_name']), self.COMMAND_NAME,
             *args, **options)
     else:
         for tenant in get_tenant_model().objects.all():
             if not (options['skip_public']
                     and tenant.schema_name == get_public_schema_name()):
                 self.execute_command(tenant, self.COMMAND_NAME, *args,
                                      **options)
Пример #8
0
    def allow_migrate(self, db, app_label, model_name=None, **hints):
        # 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 tenants.utils import get_public_schema_name, app_labels

        if isinstance(app_label, ModelBase):
            # In django <1.7 the `app_label` parameter is actually `model`
            app_label = app_label._meta.app_label

        if connection.schema_name == get_public_schema_name():
            if app_label not in app_labels(settings.SHARED_APPS):
                return False
        else:
            if app_label not in app_labels(settings.TENANT_APPS):
                return False

        return None
Пример #9
0
 def set_schema_to_public(self):
     """
     Instructs to stay in the common 'public' schema.
     """
     self.tenant = FakeTenant(schema_name=get_public_schema_name())
     self.schema_name = get_public_schema_name()