Loading django/db/migrations/executor.py +8 −0 Original line number Diff line number Diff line Loading @@ -180,6 +180,14 @@ class MigrationExecutor(object): def check_replacements(self): """ Mark replacement migrations applied if their replaced set all are. We do this unconditionally on every migrate, rather than just when migrations are applied or unapplied, so as to correctly handle the case when a new squash migration is pushed to a deployment that already had all its replaced migrations applied. In this case no new migration will be applied, but we still want to correctly maintain the applied state of the squash migration. """ applied = self.recorder.applied_migrations() for key, migration in self.loader.replacements.items(): Loading tests/migrations/test_executor.py +24 −0 Original line number Diff line number Diff line Loading @@ -437,6 +437,30 @@ class ExecutorTests(MigrationTestBase): recorder.applied_migrations(), ) @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) 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. Ticket #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(), ) class FakeLoader(object): def __init__(self, graph, applied): Loading Loading
django/db/migrations/executor.py +8 −0 Original line number Diff line number Diff line Loading @@ -180,6 +180,14 @@ class MigrationExecutor(object): def check_replacements(self): """ Mark replacement migrations applied if their replaced set all are. We do this unconditionally on every migrate, rather than just when migrations are applied or unapplied, so as to correctly handle the case when a new squash migration is pushed to a deployment that already had all its replaced migrations applied. In this case no new migration will be applied, but we still want to correctly maintain the applied state of the squash migration. """ applied = self.recorder.applied_migrations() for key, migration in self.loader.replacements.items(): Loading
tests/migrations/test_executor.py +24 −0 Original line number Diff line number Diff line Loading @@ -437,6 +437,30 @@ class ExecutorTests(MigrationTestBase): recorder.applied_migrations(), ) @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"}) 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. Ticket #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(), ) class FakeLoader(object): def __init__(self, graph, applied): Loading