Пример #1
0
 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.')
Пример #2
0
 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)
Пример #3
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 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
Пример #4
0
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)
Пример #5
0
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()
Пример #6
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 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
Пример #7
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 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
Пример #8
0
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()
Пример #9
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 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
Пример #10
0
    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)
Пример #11
0
def get_current_tenant():
    return connections[get_tenant_database_alias()].tenant
Пример #12
0
    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()
Пример #13
0
 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()
Пример #14
0
    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()