summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2021-08-02 11:07:58 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-08-04 09:57:32 +0200
commit910ecd1b8df7678f45c3d507dde6bcb1faafa243 (patch)
tree7175c8df7bbfcacd2f9e0da34d8c216c253dbd54
parent202d3e193a33278311eb68f7c5727901e9b99b43 (diff)
Fixed #29063 -- Fixed migrate crash when specifying a name of partially applied squashed migrations.
-rw-r--r--django/core/management/commands/migrate.py11
-rw-r--r--tests/migrations/test_commands.py28
2 files changed, 38 insertions, 1 deletions
diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py
index 55b8faf38b..34fcb9bc58 100644
--- a/django/core/management/commands/migrate.py
+++ b/django/core/management/commands/migrate.py
@@ -140,7 +140,16 @@ class Command(BaseCommand):
except KeyError:
raise CommandError("Cannot find a migration matching '%s' from app '%s'." % (
migration_name, app_label))
- targets = [(app_label, migration.name)]
+ target = (app_label, migration.name)
+ # Partially applied squashed migrations are not included in the
+ # graph, use the last replacement instead.
+ if (
+ target not in executor.loader.graph.nodes and
+ target in executor.loader.replacements
+ ):
+ incomplete_migration = executor.loader.replacements[target]
+ target = incomplete_migration.replaces[-1]
+ targets = [target]
target_app_labels_only = False
elif options['app_label']:
targets = [key for key in executor.loader.graph.leaf_nodes() if key[0] == app_label]
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index b0cb0bb0b6..daeeaf8edb 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -951,6 +951,34 @@ class MigrateTests(MigrationTestBase):
)
# No changes were actually applied so there is nothing to rollback
+ def test_migrate_partially_applied_squashed_migration(self):
+ """
+ Migrating to a squashed migration specified by name should succeed
+ even if it is partially applied.
+ """
+ with self.temporary_migration_module(module='migrations.test_migrations'):
+ recorder = MigrationRecorder(connection)
+ try:
+ call_command('migrate', 'migrations', '0001_initial', verbosity=0)
+ call_command(
+ 'squashmigrations',
+ 'migrations',
+ '0002',
+ interactive=False,
+ verbosity=0,
+ )
+ call_command(
+ 'migrate',
+ 'migrations',
+ '0001_squashed_0002_second',
+ verbosity=0,
+ )
+ applied_migrations = recorder.applied_migrations()
+ self.assertIn(('migrations', '0002_second'), applied_migrations)
+ finally:
+ # Unmigrate everything.
+ call_command('migrate', 'migrations', 'zero', verbosity=0)
+
@override_settings(MIGRATION_MODULES={'migrations': 'migrations.test_migrations'})
def test_migrate_inconsistent_history(self):
"""