Exemplo n.º 1
0
    def handle(self, *args, **options):
        # Get the database we're operating from
        connection = connections[options['database']]

        # Load up an executor to get all the migration data
        executor = MigrationExecutor(connection)

        # Resolve command-line arguments into a migration
        app_label, migration_name = options['app_label'], options['migration_name']
        if app_label not in executor.loader.migrated_apps:
            raise CommandError("App '%s' does not have migrations" % app_label)
        try:
            migration = executor.loader.get_migration_by_prefix(app_label, migration_name)
        except AmbiguityError:
            raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % (
                migration_name, app_label))
        except KeyError:
            raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % (
                migration_name, app_label))
        targets = [(app_label, migration.name)]

        # Show begin/end around output only for atomic migrations
        self.output_transaction = migration.atomic

        # Make a plan that represents just the requested migrations and show SQL
        # for it
        plan = [(executor.loader.graph.nodes[targets[0]], options['backwards'])]
        sql_statements = executor.collect_sql(plan)
        return '\n'.join(sql_statements)
Exemplo n.º 2
0
    def handle(self, *args, **options):

        # Get the database we're operating from
        db = options.get('database')
        connection = connections[db]

        # Load up an executor to get all the migration data
        executor = MigrationExecutor(connection)

        # Resolve command-line arguments into a migration
        if len(args) != 2:
            raise CommandError("Wrong number of arguments (expecting 'sqlmigrate app_label migrationname')")
        else:
            app_label, migration_name = args
            if app_label not in executor.loader.migrated_apps:
                raise CommandError("App '%s' does not have migrations" % app_label)
            try:
                migration = executor.loader.get_migration_by_prefix(app_label, migration_name)
            except AmbiguityError:
                raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % (
                    migration_name, app_label))
            except KeyError:
                raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % (
                    migration_name, app_label))
            targets = [(app_label, migration.name)]

        # Make a plan that represents just the requested migrations and show SQL
        # for it
        plan = [(executor.loader.graph.nodes[targets[0]], options.get("backwards", False))]
        sql_statements = executor.collect_sql(plan)
        for statement in sql_statements:
            self.stdout.write(statement)
Exemplo n.º 3
0
    def handle(self, *args, **options):
        # Get the database we're operating from
        connection = connections[options['database']]

        # Load up an executor to get all the migration table_s
        executor = MigrationExecutor(connection)

        # Resolve command-line arguments into a migration
        app_label, migration_name = options['app_label'], options['migration_name']
        if app_label not in executor.loader.migrated_apps:
            raise CommandError("App '%s' does not have migrations" % app_label)
        try:
            migration = executor.loader.get_migration_by_prefix(app_label, migration_name)
        except AmbiguityError:
            raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % (
                migration_name, app_label))
        except KeyError:
            raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % (
                migration_name, app_label))
        targets = [(app_label, migration.name)]

        # Show begin/end around output only for atomic migrations
        self.output_transaction = migration.atomic

        # Make a plan that represents just the requested migrations and show SQL
        # for it
        plan = [(executor.loader.graph.nodes[targets[0]], options['backwards'])]
        sql_statements = executor.collect_sql(plan)
        return '\n'.join(sql_statements)
Exemplo n.º 4
0
    def handle(self, *args, **options):

        # Get the database we're operating from
        db = options.get('database')
        connection = connections[db]

        # Load up an executor to get all the migration data
        executor = MigrationExecutor(connection)

        # Resolve command-line arguments into a migration
        if len(args) != 2:
            raise CommandError("Wrong number of arguments (expecting 'sqlmigrate app_label migrationname')")
        else:
            app_label, migration_name = args
            if app_label not in executor.loader.migrated_apps:
                raise CommandError("App '%s' does not have migrations" % app_label)
            try:
                migration = executor.loader.get_migration_by_prefix(app_label, migration_name)
            except AmbiguityError:
                raise CommandError("More than one migration matches '%s' in app '%s'. Please be more specific." % (
                    migration_name, app_label))
            except KeyError:
                raise CommandError("Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?" % (
                    migration_name, app_label))
            targets = [(app_label, migration.name)]

        # Make a plan that represents just the requested migrations and show SQL
        # for it
        plan = [(executor.loader.graph.nodes[targets[0]], options.get("backwards", False))]
        sql_statements = executor.collect_sql(plan)
        return '\n'.join(sql_statements)
def as_string_with_sql_annotations(self, *args, **kwargs):
    connection = connections[DEFAULT_DB_ALIAS]

    # check allowed engines in settings
    allowed_engines = get_setting("ALLOW_ENGINES")
    if allowed_engines and connection.vendor not in allowed_engines:
        raise Exception("You are not allowed to generate migrations files "
                        "with the DB engine '%s'. Please use an engine among "
                        "the following list: %s" % (
                            connection.vendor,
                            ", ".join(allowed_engines),
                        ))

    content = self._original_as_string(*args, **kwargs)
    assert "\nclass Migration" in content, "couldn't find 'class Migration' in migration content"

    # write migration un-processed so the executor can find/read it
    with open(self.path, "w") as f:
        f.write(content)

    # get SQL code
    executor = MigrationExecutor(connection)
    app_label = self.migration.app_label
    mirgation_name = self.migration.name
    plan = [(executor.loader.graph.nodes[(app_label, mirgation_name)], False)]
    sql_statements = executor.collect_sql(plan)

    # amend content that will be written to disk
    comment = "\n".join("# %s" % stmt for stmt in sql_statements)
    comment = "# Generated SQL code (%s):\n#\n%s\n#\n" % (connection.vendor,
                                                          comment)

    # check rules
    rules = get_setting("RULES")
    check_results = []
    for rule in rules:
        status = rule().process(self.migration, sql_statements)
        out = (status, rule.title)
        check_results.append(out)

    if check_results:
        comment += "\n# Check results:\n"
    for res in check_results:
        comment += "# CHECK %s: %s\n" % (res[0], res[1])

    content = content.replace(
        "\nclass Migration",
        "\n%sclass Migration" % comment,
    )

    return content
Exemplo n.º 6
0
    def handle(self, *args, **options):
        # Get the database we're operating from
        connection = connections[options["database"]]

        # Load up an executor to get all the migration data
        executor = MigrationExecutor(connection)

        # Resolve command-line arguments into a migration
        app_label, migration_name = options["app_label"], options[
            "migration_name"]
        # Validate app_label
        try:
            apps.get_app_config(app_label)
        except LookupError as err:
            raise CommandError(str(err))
        if app_label not in executor.loader.migrated_apps:
            raise CommandError("App '%s' does not have migrations" % app_label)
        try:
            migration = executor.loader.get_migration_by_prefix(
                app_label, migration_name)
        except AmbiguityError:
            raise CommandError(
                "More than one migration matches '%s' in app '%s'. Please be more specific."
                % (migration_name, app_label))
        except KeyError:
            raise CommandError(
                "Cannot find a migration matching '%s' from app '%s'. Is it in INSTALLED_APPS?"
                % (migration_name, app_label))
        targets = [(app_label, migration.name)]

        # Show begin/end around output for atomic migrations, if the database
        # supports transactional DDL.
        self.output_transaction = (migration.atomic
                                   and connection.features.can_rollback_ddl)

        # Make a plan that represents just the requested migrations and show SQL
        # for it
        plan = [(executor.loader.graph.nodes[targets[0]], options["backwards"])
                ]
        sql_statements = executor.collect_sql(plan)
        if not sql_statements and options["verbosity"] >= 1:
            self.stderr.write("No operations found.")
        return "\n".join(sql_statements)
Exemplo n.º 7
0
    def handle(self, *args, **options):

        self.verbosity = options.get('verbosity')
        self.interactive = options.get('interactive')
        self.show_traceback = options.get('traceback')
        self.load_initial_data = options.get('load_initial_data')
        db_dry_run = options.get("db_dry_run")

        # Get the database we're operating from
        db = options.get('database')
        connection = connections[db]

        # If they asked for a migration listing, quit main execution flow and show it
        if options.get("list", False):
            warnings.warn(
                "The 'migrate --list' command is deprecated. Use 'showmigrations' instead.",
                RemovedInDjango110Warning, stacklevel=2)
            self.stdout.ending = None  # Remove when #21429 is fixed
            return call_command(
                'showmigrations',
                '--list',
                app_labels=[options['app_label']] if options['app_label'] else None,
                database=db,
                no_color=options.get('no_color'),
                settings=options.get('settings'),
                stdout=self.stdout,
                traceback=self.show_traceback,
                verbosity=self.verbosity,
            )

        # Hook for backends needing any database preparation
        connection.prepare_database()
        # Work out which apps have migrations and which do not
        executor = MigrationExecutor(connection, self.migration_progress_callback)

        # Before anything else, see if there's conflicting apps and drop out
        # hard if there are any
        conflicts = executor.loader.detect_conflicts()
        if conflicts:
            name_str = "; ".join(
                "%s in %s" % (", ".join(names), app)
                for app, names in conflicts.items()
            )
            raise CommandError(
                "Conflicting migrations detected (%s).\nTo fix them run "
                "'python manage.py makemigrations --merge'" % name_str
            )

        # If they supplied command line arguments, work out what they mean.
        run_syncdb = False
        target_app_labels_only = True
        if options['app_label'] and options['migration_name']:
            app_label, migration_name = options['app_label'], options['migration_name']
            if app_label not in executor.loader.migrated_apps:
                raise CommandError(
                    "App '%s' does not have migrations (you cannot selectively "
                    "sync unmigrated apps)" % app_label
                )
            if migration_name == "zero":
                targets = [(app_label, None)]
            else:
                try:
                    migration = executor.loader.get_migration_by_prefix(app_label, migration_name)
                except AmbiguityError:
                    raise CommandError(
                        "More than one migration matches '%s' in app '%s'. "
                        "Please be more specific." %
                        (migration_name, app_label)
                    )
                except KeyError:
                    raise CommandError("Cannot find a migration matching '%s' from app '%s'." % (
                        migration_name, app_label))
                targets = [(app_label, migration.name)]
            target_app_labels_only = False
        elif options['app_label']:
            app_label = options['app_label']
            if app_label not in executor.loader.migrated_apps:
                raise CommandError(
                    "App '%s' does not have migrations (you cannot selectively "
                    "sync unmigrated apps)" % app_label
                )
            targets = [key for key in executor.loader.graph.leaf_nodes() if key[0] == app_label]
        else:
            targets = executor.loader.graph.leaf_nodes()
            run_syncdb = True

        plan = executor.migration_plan(targets)

        # Print some useful info
        if self.verbosity >= 1:
            self.stdout.write(self.style.MIGRATE_HEADING("Operations to perform:"))
            if run_syncdb and executor.loader.unmigrated_apps:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Synchronize unmigrated apps: ") +
                    (", ".join(executor.loader.unmigrated_apps))
                )
            if target_app_labels_only:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Apply all migrations: ") +
                    (", ".join(set(a for a, n in targets)) or "(none)")
                )
            else:
                if targets[0][1] is None:
                    self.stdout.write(self.style.MIGRATE_LABEL(
                        "  Unapply all migrations: ") + "%s" % (targets[0][0], )
                    )
                else:
                    self.stdout.write(self.style.MIGRATE_LABEL(
                        "  Target specific migration: ") + "%s, from %s"
                        % (targets[0][1], targets[0][0])
                    )

        # Run the syncdb phase.
        # If you ever manage to get rid of this, I owe you many, many drinks.
        # Note that pre_migrate is called from inside here, as it needs
        # the list of models about to be installed.
        if run_syncdb and executor.loader.unmigrated_apps:
            if self.verbosity >= 1:
                self.stdout.write(self.style.MIGRATE_HEADING("Synchronizing apps without migrations:"))
            created_models = self.sync_apps(connection, executor.loader.unmigrated_apps)
        else:
            created_models = []
            emit_pre_migrate_signal([], self.verbosity, self.interactive, connection.alias)

        # The test runner requires us to flush after a syncdb but before migrations,
        # so do that here.
        if options.get("test_flush", False):
            call_command(
                'flush',
                verbosity=max(self.verbosity - 1, 0),
                interactive=False,
                database=db,
                reset_sequences=False,
                inhibit_post_migrate=True,
            )

        # Migrate!
        if self.verbosity >= 1:
            if db_dry_run:
                self.stdout.write(self.style.MIGRATE_HEADING("Running migrations dry-run:"))
            else:
                self.stdout.write(self.style.MIGRATE_HEADING("Running migrations:"))
        if not plan:
            executor.check_replacements()
            if self.verbosity >= 1:
                self.stdout.write("  No migrations to apply.")
                # If there's changes that aren't in migrations yet, tell them how to fix it.
                autodetector = MigrationAutodetector(
                    executor.loader.project_state(),
                    ProjectState.from_apps(apps),
                )
                changes = autodetector.changes(graph=executor.loader.graph)
                if changes:
                    self.stdout.write(self.style.NOTICE(
                        "  Your models have changes that are not yet reflected "
                        "in a migration, and so won't be applied."
                    ))
                    self.stdout.write(self.style.NOTICE(
                        "  Run 'manage.py makemigrations' to make new "
                        "migrations, and then re-run 'manage.py migrate' to "
                        "apply them."
                    ))
        else:
            fake = options.get("fake")
            fake_initial = options.get("fake_initial")
            if db_dry_run:
                # Print the SQL without making changes if db_dry_run is set
                sql_statements = executor.collect_sql(plan)
                return '\n'.join(sql_statements)
            else:
                executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)

        # Send the post_migrate signal, so individual apps can do whatever they need
        # to do at this point.
        emit_post_migrate_signal(created_models, self.verbosity, self.interactive, connection.alias)
Exemplo n.º 8
0
# -*- coding: utf-8 -*-
Exemplo n.º 9
0
def generate_changesets_text(connection,
                             app_names=None,
                             author=None,
                             fake=False,
                             skip_errors=False,
                             indent=''):

    author = author or os.getlogin()

    loader = MigrationLoader(connection)
    graph = loader.graph

    if app_names:
        validate_app_names(loader, app_names)

        targets = [key for key in graph.leaf_nodes() if key[0] in app_names]
    else:
        targets = graph.leaf_nodes()
    plan = []
    seen = set()

    # Generate the plan
    for target in targets:
        for migration in graph.forwards_plan(target):
            if migration not in seen:
                node = graph.node_map[migration]
                plan.append(node)
                seen.add(migration)

    to_generate = []

    for node in plan:
        if node.key not in loader.applied_migrations:
            to_generate.append(node)

    executor = MigrationExecutor(connection)

    def cdata_lines(lines, indentation_level=2):
        indent_str = indentation_level * indent
        separator = u'\n%s' % indent_str
        if len(lines) > 1:
            return u'\n%s%s\n' % (indent_str, separator.join(lines))
        else:
            return lines[0]

    outputs = []

    changesett = Template(
        '$indent<changeSet author="$author" id="$id">$body$indent</changeSet>')
    cdatat = Template('<![CDATA[$body]]>')
    sqlt = Template('$indent$indent<sql>$body</sql>')
    rollbackt = Template(
        '$indent$indent<rollback>\n$indent$body\n$indent$indent</rollback>')

    forwardt = Template('insert into django_migrations (app, name, applied) '
                        'values (\'$app_label\', \'$migration_name\', now())')
    backwardt = Template('delete from django_migrations where '
                         'app=\'$app_label\' and name=\'$migration_name\'')

    for app_label, name in to_generate:
        migration = executor.loader.get_migration_by_prefix(app_label, name)
        targets = [(app_label, migration.name)]
        forward_plan = [(executor.loader.graph.nodes[targets[0]], False)]
        backward_plan = [(executor.loader.graph.nodes[targets[0]], True)]

        try:
            sql_forward = executor.collect_sql(forward_plan)
        except Exception as ex:
            if skip_errors:
                sql_forward = ['-- skipped due to exception: %s' % ex]
            else:
                raise

        try:
            sql_backward = executor.collect_sql(backward_plan)
        except Exception as ex:
            if skip_errors:
                sql_backward = ['-- skipped due to exception: %s' % ex]
            else:
                raise

        changeset_id = u'django-%s-%s' % (app_label, migration.name)

        if fake:
            changeset_id += '-faked'

        ctx = {
            'indent': indent,
            'id': changeset_id,
            'author': author,
            'app_label': app_label,
            'migration_name': migration.name,
        }

        def rendertpl(tpl, **extra):
            tplctx = dict(ctx)
            tplctx.update(extra)
            return tpl.substitute(tplctx)

        changeset_parts = []

        if not fake:
            changeset_parts.append(u'\n' + rendertpl(
                sqlt,
                body=rendertpl(
                    cdatat,
                    body=cdata_lines(sql_forward, indentation_level=2) +
                    indent * 2)))

        changeset_parts.append(rendertpl(sqlt, body=rendertpl(forwardt)))

        rollback_parts = []

        if not fake:
            rollback_parts.append(
                rendertpl(
                    sqlt,
                    body=rendertpl(
                        cdatat,
                        body=cdata_lines(sql_backward, indentation_level=3) +
                        indent * 3)))

        rollback_parts.append(indent +
                              rendertpl(sqlt, body=rendertpl(backwardt)))

        sep = u'\n'
        changeset_parts.append(
            rendertpl(rollbackt, body=sep.join(rollback_parts)))
        outputs.append(
            rendertpl(changesett, body=sep.join(changeset_parts) + u'\n'))
    return u'\n'.join(outputs)
Exemplo n.º 10
0
    def handle(self, *args, **options):

        self.verbosity = options.get('verbosity')
        self.interactive = options.get('interactive')
        self.show_traceback = options.get('traceback')
        self.load_initial_data = options.get('load_initial_data')
        db_dry_run = options.get("db_dry_run")

        # Get the database we're operating from
        db = options.get('database')
        connection = connections[db]

        # If they asked for a migration listing, quit main execution flow and show it
        if options.get("list", False):
            self.stderr.write(
                "The 'migrate --list' command is deprecated. Use 'showmigrations' instead."
            )
            self.stdout.ending = None  # Remove when #21429 is fixed
            return call_command(
                'showmigrations',
                '--list',
                app_labels=[options['app_label']]
                if options['app_label'] else None,
                database=db,
                no_color=options.get('no_color'),
                settings=options.get('settings'),
                stdout=self.stdout,
                traceback=self.show_traceback,
                verbosity=self.verbosity,
            )

        # Hook for backends needing any database preparation
        connection.prepare_database()
        # Work out which apps have migrations and which do not
        executor = MigrationExecutor(connection,
                                     self.migration_progress_callback)

        # Before anything else, see if there's conflicting apps and drop out
        # hard if there are any
        conflicts = executor.loader.detect_conflicts()
        if conflicts:
            name_str = "; ".join("%s in %s" % (", ".join(names), app)
                                 for app, names in conflicts.items())
            raise CommandError(
                "Conflicting migrations detected (%s).\nTo fix them run "
                "'python manage.py makemigrations --merge'" % name_str)

        # If they supplied command line arguments, work out what they mean.
        run_syncdb = False
        target_app_labels_only = True
        if options['app_label'] and options['migration_name']:
            app_label, migration_name = options['app_label'], options[
                'migration_name']
            if app_label not in executor.loader.migrated_apps:
                raise CommandError(
                    "App '%s' does not have migrations (you cannot selectively "
                    "sync unmigrated apps)" % app_label)
            if migration_name == "zero":
                targets = [(app_label, None)]
            else:
                try:
                    migration = executor.loader.get_migration_by_prefix(
                        app_label, migration_name)
                except AmbiguityError:
                    raise CommandError(
                        "More than one migration matches '%s' in app '%s'. "
                        "Please be more specific." %
                        (migration_name, app_label))
                except KeyError:
                    raise CommandError(
                        "Cannot find a migration matching '%s' from app '%s'."
                        % (migration_name, app_label))
                targets = [(app_label, migration.name)]
            target_app_labels_only = False
        elif options['app_label']:
            app_label = options['app_label']
            if app_label not in executor.loader.migrated_apps:
                raise CommandError(
                    "App '%s' does not have migrations (you cannot selectively "
                    "sync unmigrated apps)" % app_label)
            targets = [
                key for key in executor.loader.graph.leaf_nodes()
                if key[0] == app_label
            ]
        else:
            targets = executor.loader.graph.leaf_nodes()
            run_syncdb = True

        plan = executor.migration_plan(targets)

        # Print some useful info
        if self.verbosity >= 1:
            self.stdout.write(
                self.style.MIGRATE_HEADING("Operations to perform:"))
            if run_syncdb and executor.loader.unmigrated_apps:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Synchronize unmigrated apps: ")
                    + (", ".join(executor.loader.unmigrated_apps)))
            if target_app_labels_only:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Apply all migrations: ") +
                    (", ".join(set(a for a, n in targets)) or "(none)"))
            else:
                if targets[0][1] is None:
                    self.stdout.write(
                        self.style.MIGRATE_LABEL("  Unapply all migrations: ")
                        + "%s" % (targets[0][0], ))
                else:
                    self.stdout.write(
                        self.style.MIGRATE_LABEL(
                            "  Target specific migration: ") + "%s, from %s" %
                        (targets[0][1], targets[0][0]))

        # Run the syncdb phase.
        # If you ever manage to get rid of this, I owe you many, many drinks.
        # Note that pre_migrate is called from inside here, as it needs
        # the list of models about to be installed.
        if run_syncdb and executor.loader.unmigrated_apps:
            if self.verbosity >= 1:
                self.stdout.write(
                    self.style.MIGRATE_HEADING(
                        "Synchronizing apps without migrations:"))
            created_models = self.sync_apps(connection,
                                            executor.loader.unmigrated_apps)
        else:
            created_models = []
            emit_pre_migrate_signal([], self.verbosity, self.interactive,
                                    connection.alias)

        # The test runner requires us to flush after a syncdb but before migrations,
        # so do that here.
        if options.get("test_flush", False):
            call_command(
                'flush',
                verbosity=max(self.verbosity - 1, 0),
                interactive=False,
                database=db,
                reset_sequences=False,
                inhibit_post_migrate=True,
            )

        # Migrate!
        if self.verbosity >= 1:
            if db_dry_run:
                self.stdout.write(
                    self.style.MIGRATE_HEADING("Running migrations dry-run:"))
            else:
                self.stdout.write(
                    self.style.MIGRATE_HEADING("Running migrations:"))
        if not plan:
            executor.check_replacements()
            if self.verbosity >= 1:
                self.stdout.write("  No migrations to apply.")
                # If there's changes that aren't in migrations yet, tell them how to fix it.
                autodetector = MigrationAutodetector(
                    executor.loader.project_state(),
                    ProjectState.from_apps(apps),
                )
                changes = autodetector.changes(graph=executor.loader.graph)
                if changes:
                    self.stdout.write(
                        self.style.NOTICE(
                            "  Your models have changes that are not yet reflected "
                            "in a migration, and so won't be applied."))
                    self.stdout.write(
                        self.style.NOTICE(
                            "  Run 'manage.py makemigrations' to make new "
                            "migrations, and then re-run 'manage.py migrate' to "
                            "apply them."))
        else:
            fake = options.get("fake")
            fake_initial = options.get("fake_initial")
            if db_dry_run:
                # Print the SQL without making changes if db_dry_run is set
                sql_statements = executor.collect_sql(plan)
                return '\n'.join(sql_statements)
            else:
                executor.migrate(targets,
                                 plan,
                                 fake=fake,
                                 fake_initial=fake_initial)

        # Send the post_migrate signal, so individual apps can do whatever they need
        # to do at this point.
        emit_post_migrate_signal(created_models, self.verbosity,
                                 self.interactive, connection.alias)