[1.8.x] Fixed #24895 -- Fixed loading a pair of squashed migrations with a dependency.

Backport of 84522c0d16 from master.
This commit is contained in:
Carl Meyer 2015-06-01 17:22:10 -06:00
parent 7f92b6e576
commit 98b40ffe61
3 changed files with 53 additions and 10 deletions

View File

@ -222,15 +222,29 @@ class MigrationLoader(object):
for child_key in reverse_dependencies.get(replaced, set()):
if child_key in migration.replaces:
continue
# child_key may appear in a replacement
# List of migrations whose dependency on `replaced` needs
# to be updated to a dependency on `key`.
to_update = []
# Child key may itself be replaced, in which case it might
# not be in `normal` anymore (depending on whether we've
# processed its replacement yet). If it's present, we go
# ahead and update it; it may be deleted later on if it is
# replaced, but there's no harm in updating it regardless.
if child_key in normal:
to_update.append(normal[child_key])
# If the child key is replaced, we update its replacement's
# dependencies too, if necessary. (We don't know if this
# replacement will actually take effect or not, but either
# way it's OK to update the replacing migration).
if child_key in reverse_replacements:
for replaced_child_key in reverse_replacements[child_key]:
if replaced in replacing[replaced_child_key].dependencies:
replacing[replaced_child_key].dependencies.remove(replaced)
replacing[replaced_child_key].dependencies.append(key)
else:
normal[child_key].dependencies.remove(replaced)
normal[child_key].dependencies.append(key)
for replaces_child_key in reverse_replacements[child_key]:
if replaced in replacing[replaces_child_key].dependencies:
to_update.append(replacing[replaces_child_key])
# Actually perform the dependency update on all migrations
# that require it.
for migration_needing_update in to_update:
migration_needing_update.dependencies.remove(replaced)
migration_needing_update.dependencies.append(key)
normal[key] = migration
# Mark the replacement as applied if all its replaced ones are
if all(applied_statuses):

View File

@ -43,3 +43,7 @@ Bugfixes
* Allowed using ``choices`` longer than 1 day with ``DurationField``
(:ticket:`24897`).
* Fixed a crash when loading squashed migrations from two apps with a
dependency between them, where the dependent app's replaced migrations are
partially applied (:ticket:`24895`).

View File

@ -259,12 +259,37 @@ class LoaderTests(TestCase):
loader.build_graph()
plan = set(loader.graph.forwards_plan(('app1', '4_auto')))
expected_plan = set([
expected_plan = {
('app1', '4_auto'),
('app1', '2_squashed_3'),
('app2', '1_squashed_2'),
('app1', '1_auto')
])
}
self.assertEqual(plan, expected_plan)
@override_settings(MIGRATION_MODULES={
"app1": "migrations.test_migrations_squashed_complex_multi_apps.app1",
"app2": "migrations.test_migrations_squashed_complex_multi_apps.app2",
})
@modify_settings(INSTALLED_APPS={'append': [
"migrations.test_migrations_squashed_complex_multi_apps.app1",
"migrations.test_migrations_squashed_complex_multi_apps.app2",
]})
def test_loading_squashed_complex_multi_apps_partially_applied(self):
loader = MigrationLoader(connection)
recorder = MigrationRecorder(connection)
recorder.record_applied('app1', '1_auto')
recorder.record_applied('app1', '2_auto')
loader.build_graph()
plan = set(loader.graph.forwards_plan(('app1', '4_auto')))
plan = plan - loader.applied_migrations
expected_plan = {
('app1', '4_auto'),
('app1', '3_auto'),
('app2', '1_squashed_2'),
}
self.assertEqual(plan, expected_plan)
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_erroneous"})