diff --git a/django/db/migrations/loader.py b/django/db/migrations/loader.py index 245879f83b..5d62e2fb10 100644 --- a/django/db/migrations/loader.py +++ b/django/db/migrations/loader.py @@ -221,8 +221,15 @@ class MigrationLoader(object): for child_key in reverse_dependencies.get(replaced, set()): if child_key in migration.replaces: continue - normal[child_key].dependencies.remove(replaced) - normal[child_key].dependencies.append(key) + # child_key may appear in a replacement + 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) normal[key] = migration # Mark the replacement as applied if all its replaced ones are if all(applied_statuses): diff --git a/tests/migrations/test_loader.py b/tests/migrations/test_loader.py index a921321525..4416a86bc9 100644 --- a/tests/migrations/test_loader.py +++ b/tests/migrations/test_loader.py @@ -239,6 +239,27 @@ class LoaderTests(TestCase): recorder.flush() + @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(self): + loader = MigrationLoader(connection) + loader.build_graph() + + plan = set(loader.graph.forwards_plan(('app1', '4_auto'))) + expected_plan = set([ + ('app1', '4_auto'), + ('app1', '2_squashed_3'), + ('app2', '1_squashed_2'), + ('app1', '1_auto') + ]) + self.assertEqual(plan, expected_plan) + @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations_squashed_erroneous"}) def test_loading_squashed_erroneous(self): "Tests loading a complex but erroneous set of squashed migrations" diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/__init__.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py new file mode 100644 index 0000000000..25edcfa290 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/1_auto.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py new file mode 100644 index 0000000000..dcd67ca101 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_auto.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [("app1", "1_auto")] + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py new file mode 100644 index 0000000000..d74691fe44 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/2_squashed_3.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + replaces = [ + ("app1", "2_auto"), + ("app1", "3_auto"), + ] + + dependencies = [("app1", "1_auto"), ("app2", "2_auto")] + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py new file mode 100644 index 0000000000..f2b64db833 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/3_auto.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [("app1", "2_auto"), ("app2", "2_auto")] + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py new file mode 100644 index 0000000000..fa36f18566 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/4_auto.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [("app1", "3_auto")] + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/__init__.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app1/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py new file mode 100644 index 0000000000..dcd67ca101 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_auto.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [("app1", "1_auto")] + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py new file mode 100644 index 0000000000..fcd43bd0c6 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/1_squashed_2.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + replaces = [ + ("app2", "1_auto"), + ("app2", "2_auto"), + ] + + dependencies = [("app1", "1_auto")] + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py new file mode 100644 index 0000000000..9743fc92a2 --- /dev/null +++ b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/2_auto.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [("app2", "1_auto")] + + operations = [ + migrations.RunPython(lambda apps, schema_editor: None) + ] diff --git a/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/__init__.py b/tests/migrations/test_migrations_squashed_complex_multi_apps/app2/__init__.py new file mode 100644 index 0000000000..e69de29bb2