Fixed #24628 -- Fixed applied status for squashed migrations.
This commit is contained in:
parent
335fc44f68
commit
492537ac18
|
@ -110,6 +110,7 @@ class MigrationExecutor(object):
|
||||||
self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
|
self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
|
||||||
else:
|
else:
|
||||||
self.unapply_migration(states[migration], migration, fake=fake)
|
self.unapply_migration(states[migration], migration, fake=fake)
|
||||||
|
self.check_replacements()
|
||||||
|
|
||||||
def collect_sql(self, plan):
|
def collect_sql(self, plan):
|
||||||
"""
|
"""
|
||||||
|
@ -176,6 +177,16 @@ class MigrationExecutor(object):
|
||||||
self.progress_callback("unapply_success", migration, fake)
|
self.progress_callback("unapply_success", migration, fake)
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
def check_replacements(self):
|
||||||
|
"""
|
||||||
|
Mark replacement migrations applied if their replaced set all are.
|
||||||
|
"""
|
||||||
|
applied = self.recorder.applied_migrations()
|
||||||
|
for key, migration in self.loader.replacements.items():
|
||||||
|
all_applied = all(m in applied for m in migration.replaces)
|
||||||
|
if all_applied and key not in applied:
|
||||||
|
self.recorder.record_applied(*key)
|
||||||
|
|
||||||
def detect_soft_applied(self, project_state, migration):
|
def detect_soft_applied(self, project_state, migration):
|
||||||
"""
|
"""
|
||||||
Tests whether a migration has been implicitly applied - that the
|
Tests whether a migration has been implicitly applied - that the
|
||||||
|
|
|
@ -251,6 +251,8 @@ class MigrationLoader(object):
|
||||||
# Mark the replacement as applied if all its replaced ones are
|
# Mark the replacement as applied if all its replaced ones are
|
||||||
if all(applied_statuses):
|
if all(applied_statuses):
|
||||||
self.applied_migrations.add(key)
|
self.applied_migrations.add(key)
|
||||||
|
# Store the replacement migrations for later checks
|
||||||
|
self.replacements = replacing
|
||||||
# Finally, make a graph and load everything into it
|
# Finally, make a graph and load everything into it
|
||||||
self.graph = MigrationGraph()
|
self.graph = MigrationGraph()
|
||||||
for key, migration in normal.items():
|
for key, migration in normal.items():
|
||||||
|
|
|
@ -47,3 +47,6 @@ Bugfixes
|
||||||
* Fixed a crash when loading squashed migrations from two apps with a
|
* Fixed a crash when loading squashed migrations from two apps with a
|
||||||
dependency between them, where the dependent app's replaced migrations are
|
dependency between them, where the dependent app's replaced migrations are
|
||||||
partially applied (:ticket:`24895`).
|
partially applied (:ticket:`24895`).
|
||||||
|
|
||||||
|
* Fixed recording of applied status for squashed (replacement) migrations
|
||||||
|
(:ticket:`24628`).
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.apps.registry import apps as global_apps
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.db.migrations.executor import MigrationExecutor
|
from django.db.migrations.executor import MigrationExecutor
|
||||||
from django.db.migrations.graph import MigrationGraph
|
from django.db.migrations.graph import MigrationGraph
|
||||||
|
from django.db.migrations.recorder import MigrationRecorder
|
||||||
from django.db.utils import DatabaseError
|
from django.db.utils import DatabaseError
|
||||||
from django.test import TestCase, modify_settings, override_settings
|
from django.test import TestCase, modify_settings, override_settings
|
||||||
|
|
||||||
|
@ -411,6 +412,31 @@ class ExecutorTests(MigrationTestBase):
|
||||||
self.assertTableNotExists("author_app_author")
|
self.assertTableNotExists("author_app_author")
|
||||||
self.assertTableNotExists("book_app_book")
|
self.assertTableNotExists("book_app_book")
|
||||||
|
|
||||||
|
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed"})
|
||||||
|
def test_apply_all_replaced_marks_replacement_as_applied(self):
|
||||||
|
"""
|
||||||
|
Applying all replaced migrations marks the replacement as applied.
|
||||||
|
|
||||||
|
Ticket #24628.
|
||||||
|
"""
|
||||||
|
recorder = MigrationRecorder(connection)
|
||||||
|
# Place the database in a state where the replaced migrations are
|
||||||
|
# partially applied: 0001 is applied, 0002 is not.
|
||||||
|
recorder.record_applied("migrations", "0001_initial")
|
||||||
|
executor = MigrationExecutor(connection)
|
||||||
|
# Use fake because we don't actually have the first migration
|
||||||
|
# applied, so the second will fail. And there's no need to actually
|
||||||
|
# create/modify tables here, we're just testing the
|
||||||
|
# MigrationRecord, which works the same with or without fake.
|
||||||
|
executor.migrate([("migrations", "0002_second")], fake=True)
|
||||||
|
|
||||||
|
# Because we've now applied 0001 and 0002 both, their squashed
|
||||||
|
# replacement should be marked as applied.
|
||||||
|
self.assertIn(
|
||||||
|
("migrations", "0001_squashed_0002"),
|
||||||
|
recorder.applied_migrations(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class FakeLoader(object):
|
class FakeLoader(object):
|
||||||
def __init__(self, graph, applied):
|
def __init__(self, graph, applied):
|
||||||
|
|
Loading…
Reference in New Issue