def handle(self, *args, **options): super(MigrateSchemasCommand, 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 executor = get_executor(codename=self.executor)(self.args, self.options) if self.sync_public: executor.run_migrations(tenants=[self.PUBLIC_SCHEMA_NAME]) 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: tenants = [self.schema_name] else: tenants = get_tenant_model().objects.only( 'schema_name').exclude( schema_name=self.PUBLIC_SCHEMA_NAME).values_list( 'schema_name', flat=True) executor.run_migrations(tenants=tenants) tenant_objects = get_tenant_model().objects.filter(schema_name__in=tenants) for tenant in tenant_objects: if not isinstance(tenant, TenantMixin): continue post_schema_migrate.send(sender=TenantMixin, tenant=tenant.serializable_fields())
def handle(self, *args, **options): super(MigrateSchemasCommand, 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 executor = get_executor(codename=self.executor)(self.args, self.options) if self.sync_public: executor.run_migrations(tenants=[self.PUBLIC_SCHEMA_NAME]) 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: tenants = [self.schema_name] else: tenants = get_tenant_model().objects.only( 'schema_name').exclude( schema_name=self.PUBLIC_SCHEMA_NAME).values_list( 'schema_name', flat=True) executor.run_migrations(tenants=tenants)
def test_tenant_schema_is_created_atomically(self): """ When saving a tenant, it's schema should be created. This should work in atomic transactions too. """ executor = get_executor() Tenant = get_tenant_model() schema_name = 'test' @transaction.atomic() def atomically_create_tenant(): t = Tenant(schema_name=schema_name) t.save() self.created = [t] if executor == 'simple': atomically_create_tenant() self.assertTrue(schema_exists(schema_name)) elif executor == 'multiprocessing': # Unfortunately, it's impossible for the multiprocessing executor # to assert atomic transactions when creating a tenant with self.assertRaises(transaction.TransactionManagementError): atomically_create_tenant()
def test_signal_on_migrate_schemas(self): """ Check signals are sent on running of migrate_schemas. """ executor = get_executor() tenant = get_tenant_model()(schema_name='test') tenant.save() domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com') domain.save() # test the signal gets called when running migrate with catch_signal(schema_migrated) as handler: call_command('migrate_schemas', interactive=False, verbosity=0) if executor == 'simple': handler.assert_has_calls([ mock.call( schema_name=get_public_schema_name(), sender=mock.ANY, signal=schema_migrated, ), mock.call(schema_name='test', sender=mock.ANY, signal=schema_migrated) ]) elif executor == 'multiprocessing': # public schema gets migrated in the current process, always handler.assert_called_once_with( schema_name=get_public_schema_name(), sender=mock.ANY, signal=schema_migrated, )
def test_migrate_schemas_order(self): """ Test the migrate schemas is determined by TENANT_MIGRATION_ORDER. """ executor = get_executor() if executor.codename != "standard": # can only test in standard executor return tenant1 = get_tenant_model().objects.create(schema_name="test") tenant2 = get_tenant_model().objects.create(schema_name="xtest") get_tenant_domain_model().objects.create(tenant=tenant1, domain="something1.test.com") get_tenant_domain_model().objects.create(tenant=tenant2, domain="something2.test.com") # test the signal gets called when running migrate with catch_signal(schema_migrated) as handler: call_command("migrate_schemas", interactive=False, verbosity=0) handler.assert_has_calls([ mock.call( schema_name=get_public_schema_name(), sender=mock.ANY, signal=schema_migrated, ), mock.call(schema_name="xtest", sender=mock.ANY, signal=schema_migrated), mock.call(schema_name="test", sender=mock.ANY, signal=schema_migrated), ])
def handle(self, *args, **options): super().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 executor = get_executor(codename=self.executor)(self.args, self.options) if self.sync_public: executor.run_migrations(tenants=[self.PUBLIC_SCHEMA_NAME]) if self.sync_tenant: if self.schema_name and self.schema_name != self.PUBLIC_SCHEMA_NAME: if not schema_exists(self.schema_name, self.options.get('database', None)): raise RuntimeError('Schema "{}" does not exist'.format( self.schema_name)) elif has_multi_type_tenants(): type_field_name = get_multi_type_database_field_name() tenants = get_tenant_model().objects.only('schema_name', type_field_name)\ .filter(schema_name=self.schema_name)\ .values_list('schema_name', type_field_name) executor.run_multi_type_migrations(tenants=tenants) else: tenants = [self.schema_name] executor.run_migrations(tenants=tenants) else: migration_order = get_tenant_migration_order() if has_multi_type_tenants(): type_field_name = get_multi_type_database_field_name() tenants = get_tenant_model().objects.only('schema_name', type_field_name)\ .exclude(schema_name=self.PUBLIC_SCHEMA_NAME)\ .values_list('schema_name', type_field_name) if migration_order is not None: tenants = tenants.order_by(*migration_order) executor.run_multi_type_migrations(tenants=tenants) else: tenants = get_tenant_model().objects.only( 'schema_name').exclude( schema_name=self.PUBLIC_SCHEMA_NAME).values_list( 'schema_name', flat=True) if migration_order is not None: tenants = tenants.order_by(*migration_order) executor.run_migrations(tenants=tenants)
def test_signal_on_tenant_create(self): """ Since migrate gets called on creating of a tenant, check the signal gets sent. """ executor = get_executor() tenant = get_tenant_model()(schema_name='test') with catch_signal(schema_migrated) as handler: tenant.save() if executor == 'simple': handler.assert_called_once_with(schema_name='test', sender=mock.ANY, signal=schema_migrated) elif executor == 'multiprocessing': # migrations run in a different process, therefore signal # will get sent in a different process as well handler.assert_not_called() domain = get_tenant_domain_model()(tenant=tenant, domain='something.test.com') domain.save() self.created = [domain, tenant]