Exemple #1
0
    def check_migrations(self):
        """
        Checks to see if the set of migrations on disk matches the
        migrations in the database. Prints a warning if they don't match.
        """
        try:
            executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
        except ImproperlyConfigured:
            # No databases are configured (or the dummy one)
            return
        except MigrationSchemaMissing:
            self.stdout.write(
                self.style.NOTICE(
                    "\nNot checking migrations as it is not possible to access/create the django_migrations table."
                )
            )
            return

        plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
        if plan:
            apps_waiting_migration = sorted(set(migration.app_label for migration, backwards in plan))
            self.stdout.write(
                self.style.NOTICE(
                    "\nYou have %(unpplied_migration_count)s unapplied migration(s). "
                    "Your project may not work properly until you apply the "
                    "migrations for app(s): %(apps_waiting_migration)s."
                    % {
                        "unpplied_migration_count": len(plan),
                        "apps_waiting_migration": ", ".join(apps_waiting_migration),
                    }
                )
            )
            self.stdout.write(self.style.NOTICE("Run 'python manage.py migrate' to apply them.\n"))
Exemple #2
0
    def check_migrations(self):
        """
        Print a warning if the set of migrations on disk don't match the
        migrations in the database.
        """
        from django.db.migrations.executor import MigrationExecutor
        try:
            executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
        except ImproperlyConfigured:
            # No databases are configured (or the dummy one)
            return

        plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
        if plan:
            apps_waiting_migration = sorted({migration.app_label for migration, backwards in plan})
            self.stdout.write(
                self.style.NOTICE(
                    "\nYou have %(unpplied_migration_count)s unapplied migration(s). "
                    "Your project may not work properly until you apply the "
                    "migrations for app(s): %(apps_waiting_migration)s." % {
                        "unpplied_migration_count": len(plan),
                        "apps_waiting_migration": ", ".join(apps_waiting_migration),
                    }
                )
            )
            self.stdout.write(self.style.NOTICE("Run 'python manage.py migrate' to apply them.\n"))
Exemple #3
0
    def _migrate_from_old_targets(self, tmp_path):
        if "sqlite3" in self.databases['default']['ENGINE']:
            try:
                delete_path(self.databases['default']['NAME'])
            except Exception:
                self.clear(False)
                setup_from_none()
            self.read()
        else:
            self.clear(False)

        from django.db import DEFAULT_DB_ALIAS, connections
        from django.apps import apps
        from django.utils.module_loading import module_has_submodule
        from django.db.migrations.executor import MigrationExecutor
        from django.core.management.sql import emit_pre_migrate_signal, emit_post_migrate_signal

        for app_config in apps.get_app_configs():
            if module_has_submodule(app_config.module, "management"):
                import_module('.management', app_config.name)

        connection = connections[DEFAULT_DB_ALIAS]
        connection.prepare_database()
        executor = MigrationExecutor(connection)
        emit_pre_migrate_signal(0, None, connection.alias)
        executor.migrate(executor.loader.graph.leaf_nodes())
        emit_post_migrate_signal(0, None, connection.alias)
        self.clear(True, ['django_migrations'])
Exemple #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)
        for statement in sql_statements:
            self.stdout.write(statement)
 def handle(self, addrport, **kwargs):
     # In auto-reload mode, migrations will be re-made and the server will be reloaded (fixtures are not reloaded)
     for app in apps.get_app_configs():
         if app.name in settings.SCAPL_INSTALLED_APPS:
             call_command('makemigrations', app.label, interactive=False)
     call_command('migrate')
     try:
         executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
         executor.migration_plan(executor.loader.graph.leaf_nodes())
     except Exception as e:
         logger.error("Something failed with migrations execution")
         for l in str(e).split():
             logger.error(l)
         return
     if os.environ.get('RUN_MAIN') != 'true' and kwargs.get('fixtures'):
         dir = settings.SMUGGLER_FIXTURE_DIR
         for fn in sorted([f for f in os.listdir(dir) if f.endswith('.json')]):
             fixture = os.path.join(dir, fn)
             print("{}, ".format(fixture)),
             try:
                 call_command('loaddata', fixture, ignorenonexistent=True)
             except Exception as e:
                 print("No fixture loaded")
                 if isinstance(e, TypeError):
                     logger.warning("   +---> Please refer to 'BUGFIX' in the 'data' folder for this kind of error")
                 else:
                     with open(fixture) as f:
                         if f.read().strip(" \n[]") == "":
                             logger.warning("   +---> This fixture is emtpy")
     call_command('runserver', addrport)
Exemple #6
0
    def check_migrations(self):
        """
        Checks to see if the set of migrations on disk matches the
        migrations in the database. Prints a warning if they don't match.
        """
        try:
            executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
        except ImproperlyConfigured:
            # No databases are configured (or the dummy one)
            return
        except MigrationSchemaMissing:
            self.stdout.write(
                self.style.NOTICE(
                    "\nNot checking migrations as it is not possible to access/create the django_migrations table."
                )
            )
            return

        plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
        if plan:
            self.stdout.write(
                self.style.NOTICE(
                    "\nYou have unapplied migrations; your app may not work properly until they are applied."
                )
            )
            self.stdout.write(self.style.NOTICE("Run 'python manage.py migrate' to apply them.\n"))
Exemple #7
0
        def __call__(self):
            # Run the migration to test
            executor = MigrationExecutor(connection)
            executor.loader.build_graph()  # reload.
            executor.migrate(self._to)

            self.apps = executor.loader.project_state(self._to).apps
Exemple #8
0
    def test_backwards_nothing_to_do(self):
        """
        If the current state satisfies the given target, do nothing.

        a: 1 <--- 2
        b:    \- 1
        c:     \- 1

        If a1 is applied already and a2 is not, and we're asked to migrate to
        a1, don't apply or unapply b1 or c1, regardless of their current state.
        """
        a1_impl = FakeMigration('a1')
        a1 = ('a', '1')
        a2_impl = FakeMigration('a2')
        a2 = ('a', '2')
        b1_impl = FakeMigration('b1')
        b1 = ('b', '1')
        c1_impl = FakeMigration('c1')
        c1 = ('c', '1')
        graph = MigrationGraph()
        graph.add_node(a1, a1_impl)
        graph.add_node(a2, a2_impl)
        graph.add_node(b1, b1_impl)
        graph.add_node(c1, c1_impl)
        graph.add_dependency(None, a2, a1)
        graph.add_dependency(None, b1, a1)
        graph.add_dependency(None, c1, a1)

        executor = MigrationExecutor(None)
        executor.loader = FakeLoader(graph, {a1, b1})

        plan = executor.migration_plan({a1})

        self.assertEqual(plan, [])
Exemple #9
0
    def test_alter_id_type_with_fk(self):
        try:
            executor = MigrationExecutor(connection)
            self.assertTableNotExists("author_app_author")
            self.assertTableNotExists("book_app_book")
            # Apply initial migrations
            executor.migrate([
                ("author_app", "0001_initial"),
                ("book_app", "0001_initial"),
            ])
            self.assertTableExists("author_app_author")
            self.assertTableExists("book_app_book")
            # Rebuild the graph to reflect the new DB state
            executor.loader.build_graph()

            # Apply PK type alteration
            executor.migrate([("author_app", "0002_alter_id")])

            # Rebuild the graph to reflect the new DB state
            executor.loader.build_graph()
        finally:
            # We can't simply unapply the migrations here because there is no
            # implicit cast from VARCHAR to INT on the database level.
            with connection.schema_editor() as editor:
                editor.execute(editor.sql_delete_table % {"table": "book_app_book"})
                editor.execute(editor.sql_delete_table % {"table": "author_app_author"})
            self.assertTableNotExists("author_app_author")
            self.assertTableNotExists("book_app_book")
Exemple #10
0
        def __init__(self, _from, _to):
            self._to = _to
            executor = MigrationExecutor(connection)
            self.apps = executor.loader.project_state(_from).apps

            # Reverse to the original migration
            executor.migrate(_from)
Exemple #11
0
def main():
    if len(sys.argv) == 1:
        print("Usage: ./run.py run")
        return

    if sys.argv[1] in ('makemigrations', 'runserver',):
        execute_from_command_line(sys.argv)
    elif sys.argv[1] == 'run':
        from django.db.migrations.executor import MigrationExecutor

        connection = connections[DEFAULT_DB_ALIAS]
        connection.prepare_database()
        executor = MigrationExecutor(connection)
        plan = executor.migration_plan(executor.loader.graph.leaf_nodes())

        if len(plan) > 0:
            print('Synchronizing database schemas...')
            call_command('migrate')
            print()
            print('Starting application...')

        loop = asyncio.get_event_loop()

        ika = Server()
        ika.register_services()

        try:
            loop.run_until_complete(ika.connect())
        except KeyboardInterrupt:
            ika.disconnect('Manually interrupted by console access')
        except:
            ika.disconnect('Exception has occured in the main loop')
            logger.exception('Exception has occured in the main loop')
        finally:
            loop.close()
Exemple #12
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)
    def test_empty_plan(self):
        """
        Tests that re-planning a full migration of a fully-migrated set doesn't
        perform spurious unmigrations and remigrations.

        There was previously a bug where the executor just always performed the
        backwards plan for applied migrations - which even for the most recent
        migration in an app, might include other, dependent apps, and these
        were being unmigrated.
        """
        # Make the initial plan, check it
        # We use 'sessions' here as the second app as it's always present
        # in INSTALLED_APPS, so we can happily assign it test migrations.
        executor = MigrationExecutor(connection)
        plan = executor.migration_plan([("migrations", "0002_second"), ("sessions", "0001_initial")])
        self.assertEqual(
            plan,
            [
                (executor.loader.graph.nodes["migrations", "0001_initial"], False),
                (executor.loader.graph.nodes["migrations", "0002_second"], False),
                (executor.loader.graph.nodes["sessions", "0001_initial"], False),
            ],
        )
        # Fake-apply all migrations
        executor.migrate([("migrations", "0002_second"), ("sessions", "0001_initial")], fake=True)
        # Rebuild the graph to reflect the new DB state
        executor.loader.build_graph()
        # Now plan a second time and make sure it's empty
        plan = executor.migration_plan([("migrations", "0002_second"), ("sessions", "0001_initial")])
        self.assertEqual(plan, [])
        # Erase all the fake records
        executor.recorder.flush()
Exemple #14
0
    def test_minimize_rollbacks(self):
        """
        Minimize unnecessary rollbacks in connected apps.

        When you say "./manage.py migrate appA 0001", rather than migrating to
        just after appA-0001 in the linearized migration plan (which could roll
        back migrations in other apps that depend on appA 0001, but don't need
        to be rolled back since we're not rolling back appA 0001), we migrate
        to just before appA-0002.
        """
        a1_impl = FakeMigration('a1')
        a1 = ('a', '1')
        a2_impl = FakeMigration('a2')
        a2 = ('a', '2')
        b1_impl = FakeMigration('b1')
        b1 = ('b', '1')
        graph = MigrationGraph()
        graph.add_node(a1, a1_impl)
        graph.add_node(a2, a2_impl)
        graph.add_node(b1, b1_impl)
        graph.add_dependency(None, b1, a1)
        graph.add_dependency(None, a2, a1)

        executor = MigrationExecutor(None)
        executor.loader = FakeLoader(graph, {a1, b1, a2})

        plan = executor.migration_plan({a1})

        self.assertEqual(plan, [(a2_impl, True)])
 def check_migrations(self):
     """
     Checks to see if the set of migrations on disk matches the
     migrations in the database. Prints a warning if they don't match.
     """
     executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
     plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
     if plan and self.show_startup_messages:
         self.stdout.write(self.style.NOTICE("\nYou have unapplied migrations; your app may not work properly until they are applied."))
         self.stdout.write(self.style.NOTICE("Run 'python manage.py migrate' to apply them.\n"))
Exemple #16
0
def get_database_info(database=DEFAULT_DB_ALIAS):
    connection = connections[database]
    connection.prepare_database()
    executor = MigrationExecutor(connection)
    targets = executor.loader.graph.leaf_nodes()
    is_synchronized = False if executor.migration_plan(targets) else True
    return {
        'is_database_synchronized': is_synchronized,
        'postgres_version': str(parse_pg_version(connection.pg_version)),
    }
 def test_soft_apply(self):
     """
     Tests detection of initial migrations already having been applied.
     """
     state = {"faked": None}
     def fake_storer(phase, migration, fake):
         state["faked"] = fake
     executor = MigrationExecutor(connection, progress_callback=fake_storer)
     executor.recorder.flush()
     # Were the tables there before?
     self.assertTableNotExists("migrations_author")
     self.assertTableNotExists("migrations_tribble")
     # Run it normally
     executor.migrate([("migrations", "0001_initial")])
     # Are the tables there now?
     self.assertTableExists("migrations_author")
     self.assertTableExists("migrations_tribble")
     # We shouldn't have faked that one
     self.assertEqual(state["faked"], False)
     # Rebuild the graph to reflect the new DB state
     executor.loader.build_graph()
     # Fake-reverse that
     executor.migrate([("migrations", None)], fake=True)
     # Are the tables still there?
     self.assertTableExists("migrations_author")
     self.assertTableExists("migrations_tribble")
     # Make sure that was faked
     self.assertEqual(state["faked"], True)
     # Finally, migrate forwards; this should fake-apply our initial migration
     executor.migrate([("migrations", "0001_initial")])
     self.assertEqual(state["faked"], True)
     # And migrate back to clean up the database
     executor.migrate([("migrations", None)])
     self.assertTableNotExists("migrations_author")
     self.assertTableNotExists("migrations_tribble")
Exemple #18
0
 def test_atomic_operation_in_non_atomic_migration(self):
     """
     An atomic operation is properly rolled back inside a non-atomic
     migration.
     """
     executor = MigrationExecutor(connection)
     with self.assertRaisesMessage(RuntimeError, "Abort migration"):
         executor.migrate([("migrations", "0001_initial")])
     migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).apps
     Editor = migrations_apps.get_model("migrations", "Editor")
     self.assertFalse(Editor.objects.exists())
Exemple #19
0
 def test_migrations_applied_and_recorded_atomically(self):
     """Migrations are applied and recorded atomically."""
     executor = MigrationExecutor(connection)
     with mock.patch('django.db.migrations.executor.MigrationExecutor.record_migration') as record_migration:
         record_migration.side_effect = RuntimeError('Recording migration failed.')
         with self.assertRaisesMessage(RuntimeError, 'Recording migration failed.'):
             executor.migrate([('migrations', '0001_initial')])
     # The migration isn't recorded as applied since it failed.
     migration_recorder = MigrationRecorder(connection)
     self.assertFalse(migration_recorder.migration_qs.filter(app='migrations', name='0001_initial').exists())
     self.assertTableNotExists('migrations_author')
 def test_for_missing_migrations(self):
     """Checks if there're models changes which aren't reflected in migrations."""
     migrations_loader = MigrationExecutor(connection).loader
     migrations_detector = MigrationAutodetector(
         from_state=migrations_loader.project_state(),
         to_state=ProjectState.from_apps(apps)
     )
     if migrations_detector.changes(graph=migrations_loader.graph):
         self.fail(
             'Your models have changes that are not yet reflected '
             'in a migration. You should add them now.'
         )
Exemple #21
0
 def test_non_atomic_migration(self):
     """
     Applying a non-atomic migration works as expected.
     """
     executor = MigrationExecutor(connection)
     with self.assertRaisesMessage(RuntimeError, "Abort migration"):
         executor.migrate([("migrations", "0001_initial")])
     self.assertTableExists("migrations_publisher")
     migrations_apps = executor.loader.project_state(("migrations", "0001_initial")).apps
     Publisher = migrations_apps.get_model("migrations", "Publisher")
     self.assertTrue(Publisher.objects.exists())
     self.assertTableNotExists("migrations_book")
 def handle(self, *args, **options):
     connection = connections[DEFAULT_DB_ALIAS]
     connection.prepare_database()
     executor = MigrationExecutor(connection)
     targets = executor.loader.graph.leaf_nodes()
     unapplied_migrations = executor.migration_plan(targets)
     if unapplied_migrations:
         self.stdout.write('The following migrations are unapplied:', self.style.ERROR)
         for migration in unapplied_migrations:
             self.stdout.write('  {}.{}'.format(migration[0].app_label, migration[0].name), self.style.MIGRATE_LABEL)
         sys.exit(1)
     self.stdout.write('All migrations have been applied. Have a nice day!', self.style.SUCCESS)
Exemple #23
0
    def test_minimize_rollbacks_branchy(self):
        r"""
        Minimize rollbacks when target has multiple in-app children.

        a: 1 <---- 3 <--\
              \ \- 2 <--- 4
               \       \
        b:      \- 1 <--- 2
        """
        a1_impl = FakeMigration('a1')
        a1 = ('a', '1')
        a2_impl = FakeMigration('a2')
        a2 = ('a', '2')
        a3_impl = FakeMigration('a3')
        a3 = ('a', '3')
        a4_impl = FakeMigration('a4')
        a4 = ('a', '4')
        b1_impl = FakeMigration('b1')
        b1 = ('b', '1')
        b2_impl = FakeMigration('b2')
        b2 = ('b', '2')
        graph = MigrationGraph()
        graph.add_node(a1, a1_impl)
        graph.add_node(a2, a2_impl)
        graph.add_node(a3, a3_impl)
        graph.add_node(a4, a4_impl)
        graph.add_node(b1, b1_impl)
        graph.add_node(b2, b2_impl)
        graph.add_dependency(None, a2, a1)
        graph.add_dependency(None, a3, a1)
        graph.add_dependency(None, a4, a2)
        graph.add_dependency(None, a4, a3)
        graph.add_dependency(None, b2, b1)
        graph.add_dependency(None, b1, a1)
        graph.add_dependency(None, b2, a2)

        executor = MigrationExecutor(None)
        executor.loader = FakeLoader(graph, {
            a1: a1_impl,
            b1: b1_impl,
            a2: a2_impl,
            b2: b2_impl,
            a3: a3_impl,
            a4: a4_impl,
        })

        plan = executor.migration_plan({a1})

        should_be_rolled_back = [b2_impl, a4_impl, a2_impl, a3_impl]
        exp = [(m, True) for m in should_be_rolled_back]
        self.assertEqual(plan, exp)
    def migrate(self, targets):
        """
        Migrate to a new state.

        MigrationExecutors can not be reloaded, as they cache the state of the
        migrations when created. Attempting to reuse one might make some
        migrations not run, as it thinks they have already been run.
        """
        executor = MigrationExecutor(connection)
        executor.migrate(targets)

        # Cant load state for apps in the initial empty state
        state_nodes = [node for node in targets if node[1] is not None]
        return executor.loader.project_state(state_nodes).apps
Exemple #25
0
    def test_backwards_deps(self):
        """
        #23474 - Migrating backwards shouldn't cause the wrong migrations to be
        unapplied.

        Migration dependencies (x -> y === y depends on x):
        m.0001 -+-> m.0002
                +-> m2.0001

        1) Migrate m2 to 0001, causing { m.0001, m2.0002 } to be applied.
        2) Migrate m to 0001. m.0001 has already been applied, so this should
           be a noop.
        """
        executor = MigrationExecutor(connection)
        executor.migrate([("migrations2", "0001_initial")])
        try:
            self.assertTableExists("migrations2_example")
            # Rebuild the graph to reflect the new DB state
            executor.loader.build_graph()
            self.assertEqual(
                executor.migration_plan([("migrations", "0001_initial")]),
                [],
            )
            executor.migrate([("migrations", "0001_initial")])
            self.assertTableExists("migrations2_example")
        finally:
            # And migrate back to clean up the database
            executor.loader.build_graph()
            executor.migrate([("migrations", None)])
            self.assertTableNotExists("migrations_author")
            self.assertTableNotExists("migrations_tribble")
    def setUp(self):
        executor = MigrationExecutor(connection)
        # Migrate to start_migration (the migration before the one you want to test)
        executor.migrate([(self.app_name, self.start_migration)])

        # Rebuild graph. Done between invocations of migrate()
        executor.loader.build_graph()

        # Run the migration you want to test
        executor.migrate([(self.app_name, self.dest_migration)])

        # This application can now be used to get the latest models for testing
        self.django_application = executor.loader.project_state(
            [(self.app_name, self.dest_migration)]
        ).apps
Exemple #27
0
    def test_mixed_plan_not_supported(self):
        """
        Although the MigrationExecutor interfaces allows for mixed migration
        plans (combined forwards and backwards migrations) this is not
        supported.
        """
        # Prepare for mixed plan
        executor = MigrationExecutor(connection)
        plan = executor.migration_plan([("migrations", "0002_second")])
        self.assertEqual(
            plan,
            [
                (executor.loader.graph.nodes["migrations", "0001_initial"], False),
                (executor.loader.graph.nodes["migrations", "0002_second"], False),
            ],
        )
        executor.migrate(None, plan)
        # Rebuild the graph to reflect the new DB state
        executor.loader.build_graph()
        self.assertIn(('migrations', '0001_initial'), executor.loader.applied_migrations)
        self.assertIn(('migrations', '0002_second'), executor.loader.applied_migrations)
        self.assertNotIn(('migrations2', '0001_initial'), executor.loader.applied_migrations)

        # Generate mixed plan
        plan = executor.migration_plan([
            ("migrations", None),
            ("migrations2", "0001_initial"),
        ])
        msg = (
            'Migration plans with both forwards and backwards migrations are '
            'not supported. Please split your migration process into separate '
            'plans of only forwards OR backwards migrations.'
        )
        with self.assertRaisesMessage(InvalidMigrationPlan, msg) as cm:
            executor.migrate(None, plan)
        self.assertEqual(
            cm.exception.args[1],
            [
                (executor.loader.graph.nodes["migrations", "0002_second"], True),
                (executor.loader.graph.nodes["migrations", "0001_initial"], True),
                (executor.loader.graph.nodes["migrations2", "0001_initial"], False),
            ],
        )
        # Rebuild the graph to reflect the new DB state
        executor.loader.build_graph()
        executor.migrate([
            ("migrations", None),
            ("migrations2", None),
        ])
        # Are the tables gone?
        self.assertTableNotExists("migrations_author")
        self.assertTableNotExists("migrations_book")
        self.assertTableNotExists("migrations2_otherauthor")
Exemple #28
0
    def __init__(self, migrate_from, migrate_to):
        self.migrate_from = migrate_from
        self.migrate_to = migrate_to

        self.executor = MigrationExecutor(connection)
        self.executor.loader.build_graph()  # reload.
        self.executor.migrate(self.migrate_from)
    def test_migrate_marks_replacement_applied_even_if_it_did_nothing(self):
        """
        A new squash migration will be marked as applied even if all its
        replaced migrations were previously already applied (#24628).
        """
        recorder = MigrationRecorder(connection)
        # Record all replaced migrations as applied
        recorder.record_applied("migrations", "0001_initial")
        recorder.record_applied("migrations", "0002_second")
        executor = MigrationExecutor(connection)
        executor.migrate([("migrations", "0001_squashed_0002")])

        # Because 0001 and 0002 are both applied, even though this migrate run
        # didn't apply anything new, their squashed replacement should be
        # marked as applied.
        self.assertIn(("migrations", "0001_squashed_0002"), recorder.applied_migrations())
Exemple #30
0
 def test_custom_user(self):
     """
     Regression test for #22325 - references to a custom user model defined in the
     same app are not resolved correctly.
     """
     executor = MigrationExecutor(connection)
     self.assertTableNotExists("migrations_author")
     self.assertTableNotExists("migrations_tribble")
     # Migrate forwards
     executor.migrate([("migrations", "0001_initial")])
     self.assertTableExists("migrations_author")
     self.assertTableExists("migrations_tribble")
     # And migrate back to clean up the database
     executor.loader.build_graph()
     executor.migrate([("migrations", None)])
     self.assertTableNotExists("migrations_author")
     self.assertTableNotExists("migrations_tribble")
Exemple #31
0
def test_migrate_to_form_question_natural_key_reverse(transactional_db):
    executor = MigrationExecutor(connection)
    app = "caluma_form"
    migrate_from = [(app, "0024_auto_20190919_1244")]
    migrate_to = [(app, "0023_auto_20190729_1448")]

    executor.migrate(migrate_from)
    old_apps = executor.loader.project_state(migrate_from).apps

    # Create some old data. Can't use factories here

    Form = old_apps.get_model(app, "Form")
    Question = old_apps.get_model(app, "Question")
    FormQuestion = old_apps.get_model(app, "FormQuestion")

    form_1 = Form.objects.create(slug="form-1")

    question_1 = Question.objects.create(type="text", slug="question-1")
    FormQuestion.objects.create(form=form_1, question=question_1)

    # Migrate backwards.
    executor.loader.build_graph()  # reload.
    with pytest.raises(DataError):
        executor.migrate(migrate_to)
Exemple #32
0
    def setUpClass(cls):
        # Capture current state before adding any apps, so we know where to restore to
        executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
        cls._original_state = executor.loader.graph.leaf_nodes()

        super().setUpClass()
Exemple #33
0
def get_pending_migrations():
    connection = connections[DEFAULT_DB_ALIAS]
    connection.prepare_database()
    executor = MigrationExecutor(connection)
    targets = executor.loader.graph.leaf_nodes()
    return executor.migration_plan(targets)
Exemple #34
0
 def tearDown(self):
     executor = MigrationExecutor(connection)
     executor.loader.build_graph()
     executor.migrate(executor.loader.graph.leaf_nodes())
Exemple #35
0
    def setUp(self):
        super(MigrationTestCase, self).setUp()

        self.executor = MigrationExecutor(connection)

        self.executor.migrate(self.migrate_from)
class Migrator(object):
    """
    Class to manage your migrations and app state.

    It is designed to be used inside the tests to ensure that migrations
    are working as intended: both data and schema migrations.

    This class can be but probably should not be used directly.
    Because we have utility test framework
    integrations for ``unitest`` and ``pytest``.

    Use them for better experience.
    """
    def __init__(
        self,
        database: Optional[str] = None,
    ) -> None:
        """That's where we initialize all required internals."""
        if database is None:
            database = DEFAULT_DB_ALIAS

        self._database: str = database
        self._executor = MigrationExecutor(connections[self._database])

    def apply_initial_migration(self, targets: MigrationSpec) -> ProjectState:
        """Reverse back to the original migration."""
        targets = normalize(targets)

        style = no_style()
        # start from clean database state
        sql.drop_models_tables(self._database, style)
        sql.flush_django_migrations_table(self._database, style)

        # prepare as broad plan as possible based on full plan
        self._executor.loader.build_graph()  # reload
        full_plan = self._executor.migration_plan(
            self._executor.loader.graph.leaf_nodes(),
            clean_start=True,
        )
        plan = truncate_plan(targets, full_plan)

        # apply all migrations from generated plan on clean database
        # (only forward, so any unexpected migration won't be applied)
        # to restore database state before tested migration
        return self._migrate(targets, plan=plan)

    def apply_tested_migration(self, targets: MigrationSpec) -> ProjectState:
        """Apply the next migration."""
        self._executor.loader.build_graph()  # reload
        return self._migrate(normalize(targets))

    def reset(self) -> None:
        """Reset the state to the most recent one."""
        call_command('migrate', verbosity=0, database=self._database)

    def _migrate(
        self,
        migration_targets: MigrationSpec,
        plan: Optional[MigrationPlan] = None,
    ) -> ProjectState:
        with _mute_migrate_signals():
            return self._executor.migrate(migration_targets, plan=plan)
Exemple #37
0
    def handle(self, *args, **options):
        self.verbosity = options['verbosity']
        self.interactive = options['interactive']

        # Import the 'management' module within each installed app, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            if module_has_submodule(app_config.module, "management"):
                import_module('.management', app_config.name)

        db_routers = [
            import_string(router)()
            for router in conf.settings.DATABASE_ROUTERS
        ]
        for connection in connections.all():
            # 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)

            # Raise an error if any migrations are applied before their dependencies.
            executor.loader.check_consistent_history(connection)

            # 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; multiple leaf nodes in the "
                    "migration graph: (%s).\nTo fix them run "
                    "'python manage.py makemigrations --merge'" % name_str)

            # If they supplied command line arguments, work out what they mean.
            targets, target_app_labels_only = self._get_targets(
                connection, executor, db_routers, options)

            plan = executor.migration_plan(targets)
            run_syncdb = options[
                'run_syncdb'] and executor.loader.unmigrated_apps

            # Print some useful info
            if self.verbosity >= 1:
                self.stdout.write(
                    self.style.MIGRATE_HEADING("Operations to perform:"))
                if run_syncdb:
                    self.stdout.write(
                        self.style.MIGRATE_LABEL(
                            "  Synchronize unmigrated apps: ") +
                        (", ".join(sorted(executor.loader.unmigrated_apps))))
                if target_app_labels_only:
                    self.stdout.write(
                        self.style.MIGRATE_LABEL("  Apply all migrations: ") +
                        (", ".join(sorted({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]))

            pre_migrate_state = executor._create_project_state(
                with_applied_migrations=True)
            pre_migrate_apps = pre_migrate_state.apps
            emit_pre_migrate_signal(
                self.verbosity,
                self.interactive,
                connection.alias,
                apps=pre_migrate_apps,
                plan=plan,
            )

            # Run the syncdb phase.
            if run_syncdb:
                self._syncdb_phase(connection, executor)

            # Migrate!
            self._migrate(plan, connection, executor, pre_migrate_state,
                          targets, options)
				'level': 'DEBUG',
				'class': 'logging.StreamHandler',
			},
		},
		'loggers': {
			# We override only this one to avoid logspam
			# while running tests.  Django warnings are
			# stil shown.
			'binder': {
				'handlers': ['console'],
				'level': 'ERROR',
			},
		}
	}
})

setup()

# Do the dance to ensure the models are synched to the DB.
# This saves us from having to include migrations
from django.core.management.commands.migrate import Command as MigrationCommand
from django.db import connections
from django.db.migrations.executor import MigrationExecutor

# This is oh so hacky....
cmd = MigrationCommand()
cmd.verbosity = 0
connection = connections['default']
executor = MigrationExecutor(connection)
cmd.sync_apps(connection, executor.loader.unmigrated_apps)
    def test_soft_apply(self):
        """
        Tests detection of initial migrations already having been applied.
        """
        state = {"faked": None}

        def fake_storer(phase, migration=None, fake=None):
            state["faked"] = fake

        executor = MigrationExecutor(connection, progress_callback=fake_storer)
        # Were the tables there before?
        self.assertTableNotExists("migrations_author")
        self.assertTableNotExists("migrations_tribble")
        # Run it normally
        self.assertEqual(
            executor.migration_plan([("migrations", "0001_initial")]),
            [
                (executor.loader.graph.nodes["migrations",
                                             "0001_initial"], False),
            ],
        )
        executor.migrate([("migrations", "0001_initial")])
        # Are the tables there now?
        self.assertTableExists("migrations_author")
        self.assertTableExists("migrations_tribble")
        # We shouldn't have faked that one
        self.assertIs(state["faked"], False)
        # Rebuild the graph to reflect the new DB state
        executor.loader.build_graph()
        # Fake-reverse that
        executor.migrate([("migrations", None)], fake=True)
        # Are the tables still there?
        self.assertTableExists("migrations_author")
        self.assertTableExists("migrations_tribble")
        # Make sure that was faked
        self.assertIs(state["faked"], True)
        # Finally, migrate forwards; this should fake-apply our initial migration
        executor.loader.build_graph()
        self.assertEqual(
            executor.migration_plan([("migrations", "0001_initial")]),
            [
                (executor.loader.graph.nodes["migrations",
                                             "0001_initial"], False),
            ],
        )
        # Applying the migration should raise a database level error
        # because we haven't given the --fake-initial option
        with self.assertRaises(DatabaseError):
            executor.migrate([("migrations", "0001_initial")])
        # Reset the faked state
        state = {"faked": None}
        # Allow faking of initial CreateModel operations
        executor.migrate([("migrations", "0001_initial")], fake_initial=True)
        self.assertIs(state["faked"], True)
        # And migrate back to clean up the database
        executor.loader.build_graph()
        executor.migrate([("migrations", None)])
        self.assertTableNotExists("migrations_author")
        self.assertTableNotExists("migrations_tribble")
Exemple #40
0
    def handle(self, *args, **options):

        self.verbosity = options['verbosity']
        self.interactive = options['interactive']

        # Import the 'management' module within each installed app, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            if module_has_submodule(app_config.module, "management"):
                import_module('.management', app_config.name)

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

        # 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)

        # Raise an error if any migrations are applied before their dependencies.
        executor.loader.check_consistent_history(connection)

        # 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; multiple leaf nodes in the "
                "migration graph: (%s).\nTo fix them run "
                "'python manage.py makemigrations --merge'" % name_str)

        # If they supplied command line arguments, work out what they mean.
        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." %
                                   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." %
                                   app_label)
            targets = [
                key for key in executor.loader.graph.leaf_nodes()
                if key[0] == app_label
            ]
        else:
            targets = executor.loader.graph.leaf_nodes()

        plan = executor.migration_plan(targets)
        run_syncdb = options['run_syncdb'] and executor.loader.unmigrated_apps

        # Print some useful info
        if self.verbosity >= 1:
            self.stdout.write(
                self.style.MIGRATE_HEADING("Operations to perform:"))
            if run_syncdb:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Synchronize unmigrated apps: ")
                    + (", ".join(sorted(executor.loader.unmigrated_apps))))
            if target_app_labels_only:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Apply all migrations: ") +
                    (", ".join(sorted(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]))

        emit_pre_migrate_signal(self.verbosity, self.interactive,
                                connection.alias)

        # Run the syncdb phase.
        if run_syncdb:
            if self.verbosity >= 1:
                self.stdout.write(
                    self.style.MIGRATE_HEADING(
                        "Synchronizing apps without migrations:"))
            self.sync_apps(connection, executor.loader.unmigrated_apps)

        # Migrate!
        if self.verbosity >= 1:
            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['fake']
            fake_initial = options['fake_initial']
            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(self.verbosity, self.interactive,
                                 connection.alias)
Exemple #41
0
def test_migrate_to_flat_answers(transactional_db):
    executor = MigrationExecutor(connection)
    app = "form"
    migrate_from = [(app, "0017_auto_20190619_1320")]
    migrate_to = [(app, "0019_remove_answer_value_document")]

    executor.migrate(migrate_from)
    old_apps = executor.loader.project_state(migrate_from).apps

    # Create some old data. Can't use factories here

    Document = old_apps.get_model(app, "Document")
    Form = old_apps.get_model(app, "Form")
    Answer = old_apps.get_model(app, "Answer")
    Question = old_apps.get_model(app, "Question")
    FormQuestion = old_apps.get_model(app, "FormQuestion")

    main_form = Form.objects.create(slug="main-form")
    sub_form = Form.objects.create(slug="sub-form")

    main_form_question = Question.objects.create(type="form",
                                                 sub_form=sub_form,
                                                 slug="main-form-question")
    FormQuestion.objects.create(form=main_form, question=main_form_question)

    main_text_question = Question.objects.create(type="text",
                                                 slug="main-text-question")
    FormQuestion.objects.create(form=main_form, question=main_text_question)

    sub_text_question = Question.objects.create(type="text",
                                                slug="sub_1_question_1")
    FormQuestion.objects.create(form=sub_form, question=sub_text_question)

    # we need to set a temporary family, because the signals are not available
    main_document = Document.objects.create(form=main_form, family=uuid4())
    # then we set the correct family
    main_document.family = main_document.pk
    main_document.save()

    sub_document = Document.objects.create(form=sub_form,
                                           family=main_document.pk)
    sub_answer = Answer.objects.create(value="lorem ipsum",
                                       question=sub_text_question,
                                       document=sub_document)
    Answer.objects.create(value_document=sub_document,
                          question=main_form_question,
                          document=main_document)

    text_answer = Answer.objects.create(value="dolor sit",
                                        question=main_text_question,
                                        document=main_document)

    assert not sub_answer.document == main_document
    assert text_answer.document == main_document

    # Migrate forwards.
    executor.loader.build_graph()  # reload.
    executor.migrate(migrate_to)
    new_apps = executor.loader.project_state(migrate_to).apps

    # Test the new data.
    Answer = new_apps.get_model(app, "Answer")

    sub_answer = Answer.objects.get(value="lorem ipsum")
    text_answer = Answer.objects.get(value="dolor sit")

    assert Answer.objects.filter(question__type="form").count() == 0
    assert sub_answer.document.pk == main_document.pk
    assert text_answer.document.pk == main_document.pk
Exemple #42
0
class BaseCommentMigrationTest(TransactionTestCase):
    """
    Test specific migrations
        Make sure that `self.migrate_from` and `self.migrate_to` are defined.
    """
    @property
    def app(self):
        return apps.get_containing_app_config(type(self).__module__).name

    migrate_from = None
    migrate_to = None

    def setUp(self):
        super().setUp()
        assert self.migrate_to and self.migrate_from, \
            f'TestCase {type(self).__name__} must define migrate_to and migrate_from properties'
        self.migrate_from = [(self.app, self.migrate_from)]
        self.migrate_to = [(self.app, self.migrate_to)]
        self.executor = MigrationExecutor(connection)
        self.old_apps = self.executor.loader.project_state(
            self.migrate_from).apps

        self._create_data()
        # revert to the original migration
        self.executor.migrate(self.migrate_from)
        # ensure return to the latest migration, even if the test fails
        self.addCleanup(self.force_migrate)

        self.setUpBeforeMigration()
        self.executor.loader.build_graph()
        self.executor.migrate(self.migrate_to)
        self.new_apps = self.executor.loader.project_state(
            self.migrate_to).apps

    def setUpBeforeMigration(self):
        pass

    @property
    def new_model(self):
        return self.new_apps.get_model(self.app, 'Comment')

    @property
    def old_model(self):
        return self.old_apps.get_model(self.app, 'Comment')

    def force_migrate(self, migrate_to=None):
        self.executor.loader.build_graph()  # reload.
        if migrate_to is None:
            # get latest migration of current app
            migrate_to = [
                key for key in self.executor.loader.graph.leaf_nodes()
                if key[0] == self.app
            ]
        self.executor.migrate(migrate_to)

    def _create_data(self):
        self.user = User.objects.create_user(username="******")
        self.post = Post.objects.create(author=self.user,
                                        title="post 3",
                                        body="third post body")
        content_type = ContentType.objects.get(model='post')
        self.ct_object = content_type.get_object_for_this_type(id=self.post.id)
Exemple #43
0
    def handle(self, *args, **options):

        self.verbosity = int(options.get('verbosity'))
        self.interactive = options.get('interactive')
        self.show_traceback = options.get('traceback')
        self.load_initial_data = options.get('load_initial_data')
        self.test_database = options.get('test_database', False)

        # Import the 'management' module within each installed app, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            if module_has_submodule(app_config.module, "management"):
                import_module('.management', app_config.name)

        # 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):
            return self.show_migration_list(connection, args)

        # 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 len(args) > 2:
            raise CommandError(
                "Too many command-line arguments (expecting 'app_label' or 'app_label migrationname')"
            )
        elif len(args) == 2:
            app_label, migration_name = args
            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."
                        % (app_label, migration_name))
                except KeyError:
                    raise CommandError(
                        "Cannot find a migration matching '%s' from app '%s'."
                        % (app_label, migration_name))
                targets = [(app_label, migration.name)]
            target_app_labels_only = False
        elif len(args) == 1:
            app_label = args[0]
            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:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Synchronize unmigrated apps: ")
                    + (", ".join(executor.loader.unmigrated_apps) or "(none)"))
            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:
            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 = []

        # Migrate!
        if self.verbosity >= 1:
            self.stdout.write(
                self.style.MIGRATE_HEADING("Running migrations:"))
        if not plan:
            if self.verbosity >= 1:
                self.stdout.write("  No migrations needed.")
                # 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:
            executor.migrate(targets, plan, fake=options.get("fake", False))

        # 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)
Exemple #44
0
Finding duplicate file chunks. This needs to be done in a memory-safe, so it could take several minutes.
When the initial database query operation finishes you will start seeing additional output.

This script is incremental.  You can stop it at any time and restart it later.

DO NOT RUN MULTIPLE INSTANCES OF THIS SCRIPT AT THE SAME TIME.
""")

from django.db.migrations.executor import MigrationExecutor
from django.db import connections, DEFAULT_DB_ALIAS

connection = connections[DEFAULT_DB_ALIAS]
connection.prepare_database()
applied_migrations = set(migration_name
                         for _, migration_name in MigrationExecutor(
                             connection).loader.applied_migrations)
if "0025_auto_20200106_2153.py" in applied_migrations:
    print("\nYour chunk paths are already unique.\n")
    exit(0)

DEBUG = False

if DEBUG:
    print("\nRUNNING IN DEBUG MODE, NO DESTRUCTIVE ACTIONS WILL BE TAKEN.\n")


def run():
    duplicate_chunks, duplicate_media = get_duplicates()

    for media_file in duplicate_media:
        remove_all_but_one_chunk(media_file)
Exemple #45
0
def test_dynamic_option_unique_together(transactional_db):
    executor = MigrationExecutor(connection)
    app = "caluma_form"
    migrate_from = [(app, "0028_auto_20200210_0929")]
    migrate_to = [(app, "0029_dynamic_option_unique_together")]

    executor.migrate(migrate_from)
    old_apps = executor.loader.project_state(migrate_from).apps

    # Create some old data. Can't use factories here

    Document = old_apps.get_model(app, "Document")
    Form = old_apps.get_model(app, "Form")
    Question = old_apps.get_model(app, "Question")
    DynamicOption = old_apps.get_model(app, "DynamicOption")
    HistoricalDynamicOption = old_apps.get_model("caluma_form",
                                                 "HistoricalDynamicOption")

    form = Form.objects.create(slug="main-form")

    question = Question.objects.create(type="text", slug="main-form-question")

    # we need to set a temporary family, because the signals are not available
    document = Document.objects.create(form=form, family=uuid4())
    # then we set the correct family
    document.family = document.pk
    document.save()

    d_option_1 = DynamicOption.objects.create(document=document,
                                              question=question,
                                              slug="foo")
    d_option_2 = DynamicOption.objects.create(document=document,
                                              question=question,
                                              slug="foo")

    # again no signals
    HistoricalDynamicOption.objects.create(
        document=document,
        question=question,
        history_type="+",
        created_at=d_option_1.created_at,
        modified_at=d_option_1.modified_at,
        history_date=d_option_1.modified_at,
        slug="foo",
        id=d_option_1.pk,
    )
    HistoricalDynamicOption.objects.create(
        document=document,
        question=question,
        history_type="+",
        created_at=d_option_2.created_at,
        modified_at=d_option_2.modified_at,
        history_date=d_option_2.modified_at,
        slug="foo",
        id=d_option_2.pk,
    )

    # Migrate forwards.
    executor.loader.build_graph()  # reload.
    executor.migrate(migrate_to)
    new_apps = executor.loader.project_state(migrate_to).apps

    # Test the new data.
    DynamicOption = new_apps.get_model(app, "DynamicOption")
    HistoricalDynamicOption = new_apps.get_model("caluma_form",
                                                 "HistoricalDynamicOption")
    Document = new_apps.get_model(app, "Document")
    Question = new_apps.get_model(app, "Question")

    document = Document.objects.get(pk=document.pk)
    question = Question.objects.get(pk=question.pk)

    assert DynamicOption.objects.get(document=document,
                                     question=question,
                                     slug="foo")
    assert (HistoricalDynamicOption.objects.filter(document=document,
                                                   question=question,
                                                   slug="foo").count() == 1)
Exemple #46
0
def prevent_tests_migrate(db):
    from django.db import connections
    from django.db.migrations.executor import MigrationExecutor
    ma = MigrationExecutor(connections[db]).loader.migrated_apps
    return dict(zip(ma, ['{a}.notmigrations'.format(a=a) for a in ma]))
Exemple #47
0
 def process_request(self, request):
     executor = MigrationExecutor(connection)
     plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
     if bool(plan) and \
             getattr(resolve(request.path), 'url_name', '') != 'migrations_notran':
         return redirect(reverse("ui:migrations_notran"))
Exemple #48
0
    def handle(self, *args, **options):
        database = options['database']
        if not options['skip_checks']:
            self.check(databases=[database])

        self.verbosity = options['verbosity']
        self.interactive = options['interactive']

        # Import the 'management' module within each installed BLOG, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            if module_has_submodule(app_config.module, "management"):
                import_module('.management', app_config.name)

        # Get the database we're operating from
        connection = connections[database]

        # 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)

        # Raise an error if any migrations are applied before their dependencies.
        executor.loader.check_consistent_history(connection)

        # 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; multiple leaf nodes in the "
                "migration graph: (%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 = options['run_syncdb']
        target_app_labels_only = True
        if options['app_label']:
            # Validate app_label.
            app_label = options['app_label']
            try:
                apps.get_app_config(app_label)
            except LookupError as err:
                raise CommandError(str(err))
            if run_syncdb:
                if app_label in executor.loader.migrated_apps:
                    raise CommandError("Can't use run_syncdb with BLOG '%s' as it has migrations." % app_label)
            elif app_label not in executor.loader.migrated_apps:
                raise CommandError("App '%s' does not have migrations." % app_label)

        if options['app_label'] and options['migration_name']:
            migration_name = options['migration_name']
            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 BLOG '%s'. "
                        "Please be more specific." %
                        (migration_name, app_label)
                    )
                except KeyError:
                    raise CommandError("Cannot find a migration matching '%s' from BLOG '%s'." % (
                        migration_name, app_label))
                targets = [(app_label, migration.name)]
            target_app_labels_only = False
        elif options['app_label']:
            targets = [key for key in executor.loader.graph.leaf_nodes() if key[0] == app_label]
        else:
            targets = executor.loader.graph.leaf_nodes()

        plan = executor.migration_plan(targets)
        exit_dry = plan and options['check_unapplied']

        if options['plan']:
            self.stdout.write('Planned operations:', self.style.MIGRATE_LABEL)
            if not plan:
                self.stdout.write('  No planned migration operations.')
            for migration, backwards in plan:
                self.stdout.write(str(migration), self.style.MIGRATE_HEADING)
                for operation in migration.operations:
                    message, is_error = self.describe_operation(operation, backwards)
                    style = self.style.WARNING if is_error else None
                    self.stdout.write('    ' + message, style)
            if exit_dry:
                sys.exit(1)
            return
        if exit_dry:
            sys.exit(1)

        # At this point, ignore run_syncdb if there aren't any apps to sync.
        run_syncdb = options['run_syncdb'] and executor.loader.unmigrated_apps
        # Print some useful info
        if self.verbosity >= 1:
            self.stdout.write(self.style.MIGRATE_HEADING("Operations to perform:"))
            if run_syncdb:
                if options['app_label']:
                    self.stdout.write(
                        self.style.MIGRATE_LABEL("  Synchronize unmigrated BLOG: %s" % app_label)
                    )
                else:
                    self.stdout.write(
                        self.style.MIGRATE_LABEL("  Synchronize unmigrated apps: ") +
                        (", ".join(sorted(executor.loader.unmigrated_apps)))
                    )
            if target_app_labels_only:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Apply all migrations: ") +
                    (", ".join(sorted({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: ') +
                        str(targets[0][0])
                    )
                else:
                    self.stdout.write(self.style.MIGRATE_LABEL(
                        "  Target specific migration: ") + "%s, from %s"
                        % (targets[0][1], targets[0][0])
                    )

        pre_migrate_state = executor._create_project_state(with_applied_migrations=True)
        pre_migrate_apps = pre_migrate_state.apps
        emit_pre_migrate_signal(
            self.verbosity, self.interactive, connection.alias, apps=pre_migrate_apps, plan=plan,
        )

        # Run the syncdb phase.
        if run_syncdb:
            if self.verbosity >= 1:
                self.stdout.write(self.style.MIGRATE_HEADING("Synchronizing apps without migrations:"))
            if options['app_label']:
                self.sync_apps(connection, [app_label])
            else:
                self.sync_apps(connection, executor.loader.unmigrated_apps)

        # Migrate!
        if self.verbosity >= 1:
            self.stdout.write(self.style.MIGRATE_HEADING("Running migrations:"))
        if not plan:
            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 in BLOG(s): %s have changes that are not "
                        "yet reflected in a migration, and so won't be "
                        "applied." % ", ".join(repr(app) for app in sorted(changes))
                    ))
                    self.stdout.write(self.style.NOTICE(
                        "  Run 'manage.py makemigrations' to make new "
                        "migrations, and then re-run 'manage.py migrate' to "
                        "apply them."
                    ))
            fake = False
            fake_initial = False
        else:
            fake = options['fake']
            fake_initial = options['fake_initial']
        post_migrate_state = executor.migrate(
            targets, plan=plan, state=pre_migrate_state.clone(), fake=fake,
            fake_initial=fake_initial,
        )
        # post_migrate signals have access to all models. Ensure that all models
        # are reloaded in case any are delayed.
        post_migrate_state.clear_delayed_apps_cache()
        post_migrate_apps = post_migrate_state.apps

        # Re-render models of real apps to include relationships now that
        # we've got a final state. This wouldn't be necessary if real apps
        # models were rendered with relationships in the first place.
        with post_migrate_apps.bulk_update():
            model_keys = []
            for model_state in post_migrate_apps.real_models:
                model_key = model_state.app_label, model_state.name_lower
                model_keys.append(model_key)
                post_migrate_apps.unregister_model(*model_key)
        post_migrate_apps.render_multiple([
            ModelState.from_model(apps.get_model(*model)) for model in model_keys
        ])

        # Send the post_migrate signal, so individual apps can do whatever they need
        # to do at this point.
        emit_post_migrate_signal(
            self.verbosity, self.interactive, connection.alias, apps=post_migrate_apps, plan=plan,
        )
Exemple #49
0
    def handle(self, **options):

        self.verbosity = options.get('verbosity')
        self.interactive = options.get('interactive')
        app_label, migration_name = options['app_label'], options[
            'migration_name']

        # Load the current graph state, check the app and migration they asked for exists
        executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
        if app_label not in executor.loader.migrated_apps:
            raise CommandError(
                "App '%s' does not have migrations (so squashmigrations on it makes no sense)"
                % 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'." %
                (migration_name, app_label))

        # Work out the list of predecessor migrations
        migrations_to_squash = [
            executor.loader.get_migration(al, mn)
            for al, mn in executor.loader.graph.forwards_plan((
                migration.app_label, migration.name))
            if al == migration.app_label
        ]

        # Tell them what we're doing and optionally ask if we should proceed
        if self.verbosity > 0 or self.interactive:
            self.stdout.write(
                self.style.MIGRATE_HEADING(
                    "Will squash the following migrations:"))
            for migration in migrations_to_squash:
                self.stdout.write(" - %s" % migration.name)

            if self.interactive:
                answer = None
                while not answer or answer not in "yn":
                    answer = six.moves.input("Do you wish to proceed? [yN] ")
                    if not answer:
                        answer = "n"
                        break
                    else:
                        answer = answer[0].lower()
                if answer != "y":
                    return

        # Load the operations from all those migrations and concat together,
        # along with collecting external dependencies and detecting
        # double-squashing
        operations = []
        dependencies = set()
        for smigration in migrations_to_squash:
            if smigration.replaces:
                raise CommandError(
                    "You cannot squash squashed migrations! Please transition it to a normal migration first: https://docs.djangoproject.com/en/1.7/topics/migrations/#squashing-migrations"
                )
            operations.extend(smigration.operations)
            for dependency in smigration.dependencies:
                if isinstance(dependency, SwappableTuple):
                    if settings.AUTH_USER_MODEL == dependency.setting:
                        dependencies.add(("__setting__", "AUTH_USER_MODEL"))
                    else:
                        dependencies.add(dependency)
                elif dependency[0] != smigration.app_label:
                    dependencies.add(dependency)

        if self.verbosity > 0:
            self.stdout.write(self.style.MIGRATE_HEADING("Optimizing..."))

        optimizer = MigrationOptimizer()
        new_operations = optimizer.optimize(operations, migration.app_label)

        if self.verbosity > 0:
            if len(new_operations) == len(operations):
                self.stdout.write("  No optimizations possible.")
            else:
                self.stdout.write(
                    "  Optimized from %s operations to %s operations." %
                    (len(operations), len(new_operations)))

        # Work out the value of replaces (any squashed ones we're re-squashing)
        # need to feed their replaces into ours
        replaces = []
        for migration in migrations_to_squash:
            if migration.replaces:
                replaces.extend(migration.replaces)
            else:
                replaces.append((migration.app_label, migration.name))

        # Make a new migration with those operations
        subclass = type(
            "Migration", (migrations.Migration, ), {
                "dependencies": dependencies,
                "operations": new_operations,
                "replaces": replaces,
            })
        new_migration = subclass("0001_squashed_%s" % migration.name,
                                 app_label)

        # Write out the new migration file
        writer = MigrationWriter(new_migration)
        with open(writer.path, "wb") as fh:
            fh.write(writer.as_string())

        if self.verbosity > 0:
            self.stdout.write(
                self.style.MIGRATE_HEADING(
                    "Created new squashed migration %s" % writer.path))
            self.stdout.write(
                "  You should commit this migration but leave the old ones in place;"
            )
            self.stdout.write(
                "  the new migration will be used for new installs. Once you are sure"
            )
            self.stdout.write(
                "  all instances of the codebase have applied the migrations you squashed,"
            )
            self.stdout.write("  you can delete them.")
            if writer.needs_manual_porting:
                self.stdout.write(
                    self.style.MIGRATE_HEADING("Manual porting required"))
                self.stdout.write(
                    "  Your migrations contained functions that must be manually copied over,"
                )
                self.stdout.write(
                    "  as we could not safely copy their implementation.")
                self.stdout.write(
                    "  See the comment at the top of the squashed migration for details."
                )
    def handle(self, *args, **options):

        self.branch = options['branch']
        self.verbosity = options['verbosity']
        self.interactive = options['interactive']

        # Import the 'management' module within each installed app, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            if module_has_submodule(app_config.module, "management"):
                import_module('.management', app_config.name)

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

        # 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)

        # Raise an error if any migrations are applied before their dependencies.
        executor.loader.check_consistent_history(connection)

        targets = []
        migrations = {}
        migration_paths = self.get_diff_migrations()

        # Group diff migrations by app_label
        for p in migration_paths:
            app_label = p.parts[0]
            if app_label not in migrations:
                # Validate app_label.
                try:
                    apps.get_app_config(app_label)
                except LookupError as err:
                    raise CommandError(str(err))
                migrations[app_label] = []
            migrations[app_label].append(p.stem)

        # Get last applied migration for each app
        for app_label, migration_names in migrations.items():
            mr = MigrationRecorder.Migration.objects.filter(app=app_label)

            # Skip if already unapplied
            if not mr.filter(name__in=migration_names).count():
                continue

            mr = mr.exclude(
                name__in=migration_names).order_by('applied').last()
            if mr:
                targets.append((app_label, mr.name))

        if not targets:
            if self.verbosity >= 1:
                self.stdout.write("  No migrations to unapply.")
            return

        plan = executor.migration_plan(targets)

        if options['plan']:
            self.stdout.write('Planned operations:', self.style.MIGRATE_LABEL)
            if not plan:
                self.stdout.write('  No planned migration operations.')
            for migration, backwards in plan:
                self.stdout.write(str(migration), self.style.MIGRATE_HEADING)
                for operation in migration.operations:
                    message, is_error = self.describe_operation(
                        operation, backwards)
                    style = self.style.WARNING if is_error else None
                    self.stdout.write('    ' + message, style)
            return

        # Print some useful info
        if self.verbosity >= 1:
            self.stdout.write(
                self.style.MIGRATE_HEADING("Operations to perform:"))
            for app_label, migration_name in targets:
                self.stdout.write(
                    self.style.MIGRATE_LABEL("  Target specific migration: ") +
                    "%s, from %s" % (app_label, migration_name))

        # noinspection PyProtectedMember
        pre_migrate_state = executor._create_project_state(
            with_applied_migrations=True)
        pre_migrate_apps = pre_migrate_state.apps
        emit_pre_migrate_signal(
            self.verbosity,
            self.interactive,
            connection.alias,
            apps=pre_migrate_apps,
            plan=plan,
        )

        # Migrate!
        if self.verbosity >= 1:
            self.stdout.write(
                self.style.MIGRATE_HEADING("Running migrations:"))

        if not plan:
            fake = False
            fake_initial = False
        else:
            fake = options['fake']
            fake_initial = options['fake_initial']

        post_migrate_state = executor.migrate(
            targets,
            plan=plan,
            state=pre_migrate_state.clone(),
            fake=fake,
            fake_initial=fake_initial,
        )
        # post_migrate signals have access to all models. Ensure that all models
        # are reloaded in case any are delayed.
        post_migrate_state.clear_delayed_apps_cache()
        post_migrate_apps = post_migrate_state.apps

        # Re-render models of real apps to include relationships now that
        # we've got a final state. This wouldn't be necessary if real apps
        # models were rendered with relationships in the first place.
        with post_migrate_apps.bulk_update():
            model_keys = []
            for model_state in post_migrate_apps.real_models:
                model_key = model_state.app_label, model_state.name_lower
                model_keys.append(model_key)
                post_migrate_apps.unregister_model(*model_key)
        post_migrate_apps.render_multiple([
            ModelState.from_model(apps.get_model(*model))
            for model in model_keys
        ])

        # Send the post_migrate signal, so individual apps can do whatever they need
        # to do at this point.
        emit_post_migrate_signal(
            self.verbosity,
            self.interactive,
            connection.alias,
            apps=post_migrate_apps,
            plan=plan,
        )
Vim�UnDo��H�d�9ܟEsG��n�7��ζ���[�0l;1        BlogPost = apps.get_model("blog", "Post")0&]�W�_�����]�W���5�_�����]�W��5�_�����]�W��"from django.apps import apps from django.test import TestCase;from django.db.migrations.executor import MigrationExecutor from django.db import connectionclass TestMigrations(TestCase):
    @property    def app(self):I        return apps.get_containing_app_config(type(self).__module__).name    migrate_from = None    migrate_to = None    def setUp(self):7        assert self.migrate_from and self.migrate_to, \n            "TestCase '{}' must define migrate_from and migrate_to     properties".format(type(self).__name__);        self.migrate_from = [(self.app, self.migrate_from)]7        self.migrate_to = [(self.app, self.migrate_to)]0        executor = MigrationExecutor(connection)H        old_apps = executor.loader.project_state(self.migrate_from).apps+        # Reverse to the original migration+        executor.migrate(self.migrate_from)+        self.setUpBeforeMigration(old_apps)#        # Run the migration to test0        executor = MigrationExecutor(connection)0        executor.loader.build_graph()  # reload.)        executor.migrate(self.migrate_to)G        self.apps = executor.loader.project_state(self.migrate_to).apps5�_�$+����]�W��%�%�$5�_�&����]�W��)from django.apps import apps from django.test import TestCase;from django.db.migrations.executor import MigrationExecutor from django.db import connectionclass TestMigrations(TestCase):
    @property    def app(self):I        return apps.get_containing_app_config(type(self).__module__).name    migrate_from = None    migrate_to = None    def setUp(self):        assert (1            self.migrate_from and self.migrate_toY        ), "TestCase '{}' must define migrate_from and migrate_to     properties".format(            type(self).__name__	        );        self.migrate_from = [(self.app, self.migrate_from)]7        self.migrate_to = [(self.app, self.migrate_to)]0        executor = MigrationExecutor(connection)H        old_apps = executor.loader.project_state(self.migrate_from).apps+        # Reverse to the original migration+        executor.migrate(self.migrate_from)+        self.setUpBeforeMigration(old_apps)#        # Run the migration to test0        executor = MigrationExecutor(connection)0        executor.loader.build_graph()  # reload.)        executor.migrate(self.migrate_to)G        self.apps = executor.loader.project_state(self.migrate_to).apps)    def setUpBeforeMigration(self, apps):        pass5�_�'����]�W��(�)�'    �'5�_�)����]�W��(*<"lass TagsTestCase(TestMigrations):5�_�	)����]�W��<from django.apps import apps from django.test import TestCase;from django.db.migrations.executor import MigrationExecutor from django.db import connectionclass TestMigrations(TestCase):
    @property    def app(self):I        return apps.get_containing_app_config(type(self).__module__).name    migrate_from = None    migrate_to = None    def setUp(self):        assert (1            self.migrate_from and self.migrate_toY        ), "TestCase '{}' must define migrate_from and migrate_to     properties".format(            type(self).__name__	        );        self.migrate_from = [(self.app, self.migrate_from)]7        self.migrate_to = [(self.app, self.migrate_to)]0        executor = MigrationExecutor(connection)H        old_apps = executor.loader.project_state(self.migrate_from).apps+        # Reverse to the original migration+        executor.migrate(self.migrate_from)+        self.setUpBeforeMigration(old_apps)#        # Run the migration to test0        executor = MigrationExecutor(connection)0        executor.loader.build_graph()  # reload.)        executor.migrate(self.migrate_to)G        self.apps = executor.loader.project_state(self.migrate_to).apps)    def setUpBeforeMigration(self, apps):        pass#class TagsTestCase(TestMigrations):,    migrate_from = '0009_previous_migration'.    migrate_to = '0010_migration_being_tested')    def setUpBeforeMigration(self, apps):1        BlogPost = apps.get_model('blog', 'Post')/        self.post_id = BlogPost.objects.create(,            title = "A test post with tags",            body = "",            tags = "tag1 tag2",        ).id!    def test_tags_migrated(self):6        BlogPost = self.apps.get_model('blog', 'Post')4        post = BlogPost.objects.get(id=self.post_id).        self.assertEqual(post.tags.count(), 2)9        self.assertEqual(post.tags.all()[0].name, "tag1")9        self.assertEqual(post.tags.all()[1].name, "tag2")5�_�
	F����]�W��;Y        ), "TestCase '{}' must define migrate_from and migrate_to     properties".format(5�_�	
0&����]�W��/1;1        BlogPost = apps.get_model("blog", "Post")5�_�
0(����]�W��/1;2        BlogPost = apps.get_model("blolg", "Post")5��
Exemple #52
0
def healthcheck(request):
    executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
    plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
    status = 503 if plan else 200
    return HttpResponse(status=status)
    def test_detect_soft_applied_add_field_manytomanyfield(self):
        """
        executor.detect_soft_applied() detects ManyToManyField tables from an
        AddField operation. This checks the case of AddField in a migration
        with other operations (0001) and the case of AddField in its own
        migration (0002).
        """
        tables = [
            # from 0001
            "migrations_project",
            "migrations_task",
            "migrations_project_tasks",
            # from 0002
            "migrations_task_projects",
        ]
        executor = MigrationExecutor(connection)
        # Create the tables for 0001 but make it look like the migration hasn't
        # been applied.
        executor.migrate([("migrations", "0001_initial")])
        executor.migrate([("migrations", None)], fake=True)
        for table in tables[:3]:
            self.assertTableExists(table)
        # Table detection sees 0001 is applied but not 0002.
        migration = executor.loader.get_migration("migrations", "0001_initial")
        self.assertIs(executor.detect_soft_applied(None, migration)[0], True)
        migration = executor.loader.get_migration("migrations", "0002_initial")
        self.assertIs(executor.detect_soft_applied(None, migration)[0], False)

        # Create the tables for both migrations but make it look like neither
        # has been applied.
        executor.loader.build_graph()
        executor.migrate([("migrations", "0001_initial")], fake=True)
        executor.migrate([("migrations", "0002_initial")])
        executor.loader.build_graph()
        executor.migrate([("migrations", None)], fake=True)
        # Table detection sees 0002 is applied.
        migration = executor.loader.get_migration("migrations", "0002_initial")
        self.assertIs(executor.detect_soft_applied(None, migration)[0], True)

        # Leave the tables for 0001 except the many-to-many table. That missing
        # table should cause detect_soft_applied() to return False.
        with connection.schema_editor() as editor:
            for table in tables[2:]:
                editor.execute(editor.sql_delete_table % {"table": table})
        migration = executor.loader.get_migration("migrations", "0001_initial")
        self.assertIs(executor.detect_soft_applied(None, migration)[0], False)

        # Cleanup by removing the remaining tables.
        with connection.schema_editor() as editor:
            for table in tables[:2]:
                editor.execute(editor.sql_delete_table % {"table": table})
        for table in tables:
            self.assertTableNotExists(table)
Exemple #54
0
    def handle(self, *arg, **options):
        # it's necessary to delay this import in case
        # database migrations are still running
        from awx.main.models.ha import Instance

        executor = MigrationExecutor(connection)
        migrating = bool(
            executor.migration_plan(executor.loader.graph.leaf_nodes()))
        registered = False

        if not migrating:
            try:
                Instance.objects.me()
                registered = True
            except RuntimeError:
                pass

        if migrating or not registered:
            # In containerized deployments, migrations happen in the task container,
            # and the services running there don't start until migrations are
            # finished.
            # *This* service runs in the web container, and it's possible that it can
            # start _before_ migrations are finished, thus causing issues with the ORM
            # queries it makes (specifically, conf.settings queries).
            # This block is meant to serve as a sort of bail-out for the situation
            # where migrations aren't yet finished (similar to the migration
            # detection middleware that the uwsgi processes have) or when instance
            # registration isn't done yet
            logger.error(
                'AWX is currently installing/upgrading.  Trying again in 5s...'
            )
            time.sleep(5)
            return

        if options.get('status'):
            try:
                stats_all = BroadcastWebsocketStatsManager.get_stats_sync()
            except redis.exceptions.ConnectionError as e:
                print(
                    f"Unable to get Broadcast Websocket Status. Failed to connect to redis {e}"
                )
                return

            data = {}
            for family in stats_all:
                if family.type == 'gauge' and len(family.samples) > 1:
                    for sample in family.samples:
                        if sample.value >= 1:
                            data[family.name] = sample.labels[family.name]
                            break
                else:
                    data[family.name] = family.samples[0].value

            me = Instance.objects.me()
            hostnames = [
                i.hostname
                for i in Instance.objects.exclude(hostname=me.hostname)
            ]

            host_stats = Command.get_connection_status(me, hostnames, data)
            lines = Command._format_lines(host_stats)

            print(
                f'Broadcast websocket connection status from "{me.hostname}" to:'
            )
            print('\n'.join(lines))

            host_stats = Command.get_connection_stats(me, hostnames, data)
            lines = Command._format_lines(host_stats)

            print(
                f'\nBroadcast websocket connection stats from "{me.hostname}" to:'
            )
            print('\n'.join(lines))

            return

        try:
            broadcast_websocket_mgr = BroadcastWebsocketManager()
            task = broadcast_websocket_mgr.start()

            loop = asyncio.get_event_loop()
            loop.run_until_complete(task)
        except KeyboardInterrupt:
            logger.debug('Terminating Websocket Broadcaster')
Exemple #55
0
    def handle(self, app_label=None, migration_name=None, **options):

        self.verbosity = int(options.get('verbosity'))
        self.interactive = options.get('interactive')

        if app_label is None or migration_name is None:
            self.stderr.write(self.usage_str)
            sys.exit(1)

        # Load the current graph state, check the app and migration they asked for exists
        executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
        if app_label not in executor.loader.migrated_apps:
            raise CommandError(
                "App '%s' does not have migrations (so squashmigrations on it makes no sense)"
                % 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'." %
                (migration_name, app_label))

        # Work out the list of predecessor migrations
        migrations_to_squash = [
            executor.loader.get_migration(al, mn)
            for al, mn in executor.loader.graph.forwards_plan((
                migration.app_label, migration.name))
            if al == migration.app_label
        ]

        # Tell them what we're doing and optionally ask if we should proceed
        if self.verbosity > 0 or self.interactive:
            self.stdout.write(
                self.style.MIGRATE_HEADING(
                    "Will squash the following migrations:"))
            for migration in migrations_to_squash:
                self.stdout.write(" - %s" % migration.name)

            if self.interactive:
                answer = None
                while not answer or answer not in "yn":
                    answer = six.moves.input("Do you wish to proceed? [yN] ")
                    if not answer:
                        answer = "n"
                        break
                    else:
                        answer = answer[0].lower()
                if answer != "y":
                    return

        # Load the operations from all those migrations and concat together
        operations = []
        for smigration in migrations_to_squash:
            operations.extend(smigration.operations)

        if self.verbosity > 0:
            self.stdout.write(self.style.MIGRATE_HEADING("Optimizing..."))

        optimizer = MigrationOptimizer()
        new_operations = optimizer.optimize(operations, migration.app_label)

        if self.verbosity > 0:
            if len(new_operations) == len(operations):
                self.stdout.write("  No optimizations possible.")
            else:
                self.stdout.write(
                    "  Optimized from %s operations to %s operations." %
                    (len(operations), len(new_operations)))

        # Work out the value of replaces (any squashed ones we're re-squashing)
        # need to feed their replaces into ours
        replaces = []
        for migration in migrations_to_squash:
            if migration.replaces:
                replaces.extend(migration.replaces)
            else:
                replaces.append((migration.app_label, migration.name))

        # Make a new migration with those operations
        subclass = type(
            "Migration", (migrations.Migration, ), {
                "dependencies": [],
                "operations": new_operations,
                "replaces": replaces,
            })
        new_migration = subclass("0001_squashed_%s" % migration.name,
                                 app_label)

        # Write out the new migration file
        writer = MigrationWriter(new_migration)
        with open(writer.path, "wb") as fh:
            fh.write(writer.as_string())

        if self.verbosity > 0:
            self.stdout.write(
                self.style.MIGRATE_HEADING(
                    "Created new squashed migration %s" % writer.path))
            self.stdout.write(
                "  You should commit this migration but leave the old ones in place;"
            )
            self.stdout.write(
                "  the new migration will be used for new installs. Once you are sure"
            )
            self.stdout.write(
                "  all instances of the codebase have applied the migrations you squashed,"
            )
            self.stdout.write("  you can delete them.")
Exemple #56
0
    def flush(self, **options):
        database = options.get('database')
        connection = connections[database]
        verbosity = options.get('verbosity')
        interactive = options.get('interactive')
        # The following are stealth options used by Django's internals.
        reset_sequences = options.get('reset_sequences', True)
        allow_cascade = options.get('allow_cascade', False)
        inhibit_post_migrate = options.get('inhibit_post_migrate', False)

        self.style = no_style()

        # Import the 'management' module within each installed app, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            try:
                import_module('.management', app_config.name)
            except ImportError:
                pass

        # custom: only_django False
        # get current version before flush
        current_version = get_current_version(connection)
        sql_list = sql_flush(self.style,
                             connection,
                             only_django=False,
                             reset_sequences=reset_sequences,
                             allow_cascade=allow_cascade)

        if interactive:
            confirm = input("""You have requested a flush of the database.
This will IRREVERSIBLY DESTROY all data currently in the %r database,
and return each table to an empty state.
Are you sure you want to do this?

    Type 'yes' to continue, or 'no' to cancel: """ %
                            connection.settings_dict['NAME'])
        else:
            confirm = 'yes'

        if confirm == 'yes':
            try:
                with transaction.atomic(
                        using=database,
                        savepoint=connection.features.can_rollback_ddl):
                    with connection.cursor() as cursor:
                        for sql in sql_list:
                            cursor.execute(sql)
            except Exception as e:
                new_msg = (
                    "Database %s couldn't be flushed. Possible reasons:\n"
                    "  * The database isn't running or isn't configured "
                    "correctly.\n"
                    "  * At least one of the expected database tables doesn't "
                    "exist.\n"
                    "  * The SQL was invalid.\n"
                    "Hint: Look at the output of 'django-admin sqlflush'. "
                    "That's the SQL this command wasn't able to run.\n"
                    "The full error: %s") % (connection.settings_dict['NAME'],
                                             e)
                raise CommandError(new_msg) from e

            if not inhibit_post_migrate:
                self.emit_post_migrate(verbosity, interactive, database,
                                       current_version)

            # Reinstall the initial_data fixture.
            if options.get('load_initial_data'):
                # Remove any option that is not handle by loaddata
                # We need to load loaddata command, get its parser to extract
                # valid options
                app_name = get_commands()['loaddata']
                command = load_command_class(app_name, 'loaddata')
                parser = command.create_parser('loaddata', 'initial_data')
                valid_options = [
                    action.dest for action in parser._actions
                    if action.option_strings
                ]
                app_options = {
                    k: v
                    for k, v in options.items() if k in valid_options
                }
                # Reinstall the initial_data fixture for apps without
                # migrations.
                from django.db.migrations.executor import MigrationExecutor
                executor = MigrationExecutor(connection)
                for app_label in executor.loader.unmigrated_apps:
                    app_options['app_label'] = app_label
                    try:
                        call_command('loaddata', 'initial_data', **app_options)
                    except CommandError:
                        # fails with django 1.10 if initial_data does not exist
                        pass
        else:
            self.stdout.write("Flush cancelled.\n")
Exemple #57
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')

        # Import the 'management' module within each installed app, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            if module_has_submodule(app_config.module, "management"):
                import_module('.management', app_config.name)

        # 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.",
                RemovedInDjango20Warning,
                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:
            self.stdout.write(
                self.style.MIGRATE_HEADING("Running migrations:"))
        if not plan:
            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")
            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)
def test_fix_primary_email_migration(transactional_db):
    executor = MigrationExecutor(connection)
    app = "profiles"
    migrate_from = [(app, "0024_order_emails")]
    migrate_to = [(app, "0025_fix_primary_emails")]

    executor.migrate(migrate_from)
    old_apps = executor.loader.project_state(migrate_from).apps

    # Create some old data.
    Profile = old_apps.get_model(app, "Profile")
    Email = old_apps.get_model(app, "Email")

    profile_with_one_primary_email = Profile.objects.create()
    Email.objects.create(
        profile=profile_with_one_primary_email,
        email="*****@*****.**",
        primary=True,
    )

    profile_with_emails_but_no_primary_email = Profile.objects.create()
    Email.objects.create(
        profile=profile_with_emails_but_no_primary_email,
        email="*****@*****.**",
        primary=False,
    )

    profile_with_no_email = Profile.objects.create()

    profile_with_multiple_primary_emails = Profile.objects.create()
    Email.objects.create(
        profile=profile_with_multiple_primary_emails,
        email="*****@*****.**",
        primary=True,
    )
    Email.objects.create(
        profile=profile_with_multiple_primary_emails,
        email="*****@*****.**",
        primary=True,
    )

    # Migrate forwards.
    executor.loader.build_graph()  # reload.
    executor.migrate(migrate_to)
    new_apps = executor.loader.project_state(migrate_to).apps

    # Test the new data.
    Profile = new_apps.get_model(app, "Profile")

    profile = Profile.objects.get(pk=profile_with_one_primary_email.pk)
    assert profile.emails.filter(primary=True).count() == 1

    profile = Profile.objects.get(
        pk=profile_with_emails_but_no_primary_email.pk)
    assert profile.emails.filter(primary=True).count() == 1

    with pytest.raises(Profile.DoesNotExist):
        Profile.objects.get(pk=profile_with_no_email.pk)

    profile = Profile.objects.get(pk=profile_with_multiple_primary_emails.pk)
    assert profile.emails.filter(primary=True).count() == 1
Exemple #59
0
def is_database_synchronized(database):
    connection = connections[database]
    connection.prepare_database()
    executor = MigrationExecutor(connection)
    targets = executor.loader.graph.leaf_nodes()
    return False if executor.migration_plan(targets) else True
Exemple #60
0
    def handle_noargs(self, **options):
        database = options.get('database')
        connection = connections[database]
        verbosity = int(options.get('verbosity'))
        interactive = options.get('interactive')
        # The following are stealth options used by Django's internals.
        reset_sequences = options.get('reset_sequences', True)
        allow_cascade = options.get('allow_cascade', False)
        inhibit_post_migrate = options.get('inhibit_post_migrate', False)

        self.style = no_style()

        # Import the 'management' module within each installed app, to register
        # dispatcher events.
        for app_config in apps.get_app_configs():
            try:
                import_module('.management', app_config.name)
            except ImportError:
                pass

        sql_list = sql_flush(self.style,
                             connection,
                             only_django=True,
                             reset_sequences=reset_sequences,
                             allow_cascade=allow_cascade)

        if interactive:
            confirm = input("""You have requested a flush of the database.
This will IRREVERSIBLY DESTROY all data currently in the %r database,
and return each table to an empty state.
Are you sure you want to do this?

    Type 'yes' to continue, or 'no' to cancel: """ %
                            connection.settings_dict['NAME'])
        else:
            confirm = 'yes'

        if confirm == 'yes':
            try:
                with transaction.atomic(
                        using=database,
                        savepoint=connection.features.can_rollback_ddl):
                    with connection.cursor() as cursor:
                        for sql in sql_list:
                            cursor.execute(sql)
            except Exception as e:
                new_msg = (
                    "Database %s couldn't be flushed. Possible reasons:\n"
                    "  * The database isn't running or isn't configured correctly.\n"
                    "  * At least one of the expected database tables doesn't exist.\n"
                    "  * The SQL was invalid.\n"
                    "Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command wasn't able to run.\n"
                    "The full error: %s") % (connection.settings_dict['NAME'],
                                             e)
                six.reraise(CommandError, CommandError(new_msg),
                            sys.exc_info()[2])

            if not inhibit_post_migrate:
                self.emit_post_migrate(verbosity, interactive, database)

            # Reinstall the initial_data fixture.
            if options.get('load_initial_data'):
                # Reinstall the initial_data fixture for apps without migrations.
                from django.db.migrations.executor import MigrationExecutor
                executor = MigrationExecutor(connection)
                app_options = options.copy()
                for app_label in executor.loader.unmigrated_apps:
                    app_options['app_label'] = app_label
                    call_command('loaddata', 'initial_data', **app_options)
        else:
            self.stdout.write("Flush cancelled.\n")