def add_arguments(self, parser): super(MigrateSchemasCommand, self).add_arguments(parser) parser.add_argument('app_label', nargs='?', help='App label of an application to synchronize the state.') parser.add_argument('migration_name', nargs='?', help=( 'Database state will be brought to the state after that ' 'migration. Use the name "zero" to unapply all migrations.' ),) parser.add_argument('--noinput', action='store_false', dest='interactive', default=True, help='Tells Django to NOT prompt the user for input of any kind.') parser.add_argument('--no-initial-data', action='store_false', dest='load_initial_data', default=True, help='Tells Django not to load any initial data after database synchronization.') parser.add_argument('--database', action='store', dest='database', default=get_tenant_database_alias(), help='Nominates a database to synchronize. ' 'Defaults to the "default" database.') parser.add_argument('--fake', action='store_true', dest='fake', default=False, help='Mark migrations as run without actually running them') parser.add_argument('--fake-initial', action='store_true', dest='fake_initial', default=False, help='Detect if tables already exist and fake-apply initial migrations if so. Make sure ' 'that the current database schema matches your initial migration before using this ' 'flag. Django will only check for an existing table name.') parser.add_argument('--list', '-l', action='store_true', dest='list', default=False, help='Show a list of all known migrations and which are applied') parser.add_argument('--run-syncdb', action='store_true', dest='run_syncdb', help='Creates tables for apps without migrations.')
def handle(self, *args, **options): tenant = self.get_tenant_from_options_or_interactive(**options) connection = connections[get_tenant_database_alias()] connection.set_tenant(tenant) if isinstance(options.get('command_name'), list): options['command_name'] = options['command_name'][0] call_command(*args, **options)
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 connections from django_tenants.utils import get_public_schema_name, get_tenant_database_alias if db != get_tenant_database_alias(): return False connection = connections[db] public_schema_name = get_public_schema_name() if has_multi_type_tenants(): tenant_types = get_tenant_types() if connection.schema_name == public_schema_name: installed_apps = tenant_types[public_schema_name]['APPS'] else: installed_apps = tenant_types[ connection.tenant.tenant_type]['APPS'] else: if connection.schema_name == public_schema_name: installed_apps = settings.SHARED_APPS else: installed_apps = settings.TENANT_APPS if not self.app_in_list(app_label, installed_apps): return False return None
def run_migrations(args, options, executor_codename, schema_name, tenant_type='', allow_atomic=True, idx=None, count=None): from django.core.management import color from django.core.management.base import OutputWrapper from django.db import connections style = color.color_style() def style_func(msg): percent_str = '' if idx is not None and count is not None and count > 0: percent_str = '%d/%d (%s%%) ' % (idx + 1, count, int(100 * (idx + 1) / count)) message = '[%s%s:%s] %s' % ( percent_str, style.NOTICE(executor_codename), style.NOTICE(schema_name), msg ) signal_message = '[%s%s:%s] %s' % ( percent_str, executor_codename, schema_name, msg ) schema_migrate_message.send(run_migrations, message=signal_message) return message connection = connections[options.get('database', get_tenant_database_alias())] connection.set_schema(schema_name, tenant_type=tenant_type) # ensure that django_migrations table is created in the schema before migrations run, otherwise the migration # table in the public schema gets picked and no migrations are applied migration_recorder = MigrationRecorder(connection) migration_recorder.ensure_schema() stdout = OutputWrapper(sys.stdout) stdout.style_func = style_func stderr = OutputWrapper(sys.stderr) stderr.style_func = style_func if int(options.get('verbosity', 1)) >= 1: stdout.write(style.NOTICE("=== Starting migration")) MigrateCommand(stdout=stdout, stderr=stderr).execute(*args, **options) try: transaction.commit() connection.close() connection.connection = None except transaction.TransactionManagementError: if not allow_atomic: raise # We are in atomic transaction, don't close connections pass connection.set_schema_to_public() schema_migrated.send(run_migrations, schema_name=schema_name)
def run_migrations(args, options, executor_codename, schema_name, allow_atomic=True, idx=None, count=None): from django.core.management import color from django.core.management.base import OutputWrapper from django.db import connections style = color.color_style() def style_func(msg): percent_str = '' if idx is not None and count is not None and count > 0: percent_str = '%d/%d (%s%%) ' % (idx + 1, count, int(100 * (idx + 1) / count)) return '[%s%s:%s] %s' % (percent_str, style.NOTICE(executor_codename), style.NOTICE(schema_name), msg) include_public = True if (options.get('shared') or schema_name == 'public') else False connection = connections[get_tenant_database_alias()] connection.set_schema(schema_name, include_public=include_public) stdout = OutputWrapper(sys.stdout) stdout.style_func = style_func stderr = OutputWrapper(sys.stderr) stderr.style_func = style_func if int(options.get('verbosity', 1)) >= 1: stdout.write(style.NOTICE("=== Starting migration")) MigrateCommand(stdout=stdout, stderr=stderr).execute(*args, **options) try: transaction.commit() connection.close() connection.connection = None except transaction.TransactionManagementError: if not allow_atomic: raise # We are in atomic transaction, don't close connections pass connection.set_schema_to_public()
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 connections from django_tenants.utils import get_public_schema_name, get_tenant_database_alias if db != get_tenant_database_alias(): return False connection = connections[db] if connection.schema_name == get_public_schema_name(): if not self.app_in_list(app_label, settings.SHARED_APPS): return False else: if not self.app_in_list(app_label, settings.TENANT_APPS): return False return None
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 connections from django_tenants.utils import get_public_schema_name, get_tenant_database_alias if db != get_tenant_database_alias(): return False connection = connections[db] if connection.schema_name == get_public_schema_name(): if not self.app_in_list(app_label, settings.SHARED_APPS): return False else: if not self.app_in_list(app_label, settings.TENANT_APPS): return False return None
def run_migrations(args, options, executor_codename, schema_name, allow_atomic=True, idx=None, count=None): from django.core.management import color from django.core.management.base import OutputWrapper from django.db import connections style = color.color_style() def style_func(msg): percent_str = '' if idx is not None and count is not None and count > 0: percent_str = '%d/%d (%s%%) ' % (idx + 1, count, int(100 * (idx + 1) / count)) return '[%s%s:%s] %s' % ( percent_str, style.NOTICE(executor_codename), style.NOTICE(schema_name), msg ) connection = connections[get_tenant_database_alias()] connection.set_schema(schema_name) stdout = OutputWrapper(sys.stdout) stdout.style_func = style_func stderr = OutputWrapper(sys.stderr) stderr.style_func = style_func if int(options.get('verbosity', 1)) >= 1: stdout.write(style.NOTICE("=== Starting migration")) MigrateCommand(stdout=stdout, stderr=stderr).execute(*args, **options) try: transaction.commit() connection.close() connection.connection = None except transaction.TransactionManagementError: if not allow_atomic: raise # We are in atomic transaction, don't close connections pass connection.set_schema_to_public()
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 connections from django_tenants.utils import get_public_schema_name, get_tenant_database_alias if db != get_tenant_database_alias(): return False connection = connections[db] if connection.schema_name == get_public_schema_name(): if not self.app_in_list(app_label, settings.SHARED_APPS): return False else: # Get the tenant_type from the schema_name tenant_type = next(key for key in settings.TENANT_LISTING if connection.schema_name.endswith(key)) # Allow migrations for only those apps listed for the tenant_type if not self.app_in_list(app_label, settings.TENANT_LISTING[tenant_type]): return False return None
def run_from_argv(self, argv): """ Changes the option_list to use the options from the wrapped command. Adds schema parameter to specify which schema will be used when executing the wrapped command. """ # load the command object. if len(argv) <= 2: return try: app_name = get_commands()[argv[2]] except KeyError: raise CommandError("Unknown command: %r" % argv[2]) if isinstance(app_name, BaseCommand): # if the command is already loaded, use it directly. klass = app_name else: klass = load_command_class(app_name, argv[2]) # Ugly, but works. Delete tenant_command from the argv, parse the schema manually # and forward the rest of the arguments to the actual command being wrapped. del argv[1] schema_parser = argparse.ArgumentParser() schema_parser.add_argument("-s", "--schema", dest="schema_name", help="specify tenant schema") schema_namespace, args = schema_parser.parse_known_args(argv) tenant = self.get_tenant_from_options_or_interactive( schema_name=schema_namespace.schema_name) connection = connections[get_tenant_database_alias()] connection.set_tenant(tenant) klass.run_from_argv(args)
def get_current_tenant(): return connections[get_tenant_database_alias()].tenant
def __init__(self, args, options): self.args = args self.options = options self.PUBLIC_SCHEMA_NAME = get_public_schema_name() self.TENANT_DB_ALIAS = get_tenant_database_alias()
def __init__(self): from django_tenants.utils import get_public_schema_name, get_tenant_database_alias self.tenant_database_alias = get_tenant_database_alias() self.public_schema_name = get_public_schema_name()
def __init__(self, args, options): self.args = args self.options = options self.PUBLIC_SCHEMA_NAME = get_public_schema_name() self.TENANT_DB_ALIAS = get_tenant_database_alias()