summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2016-05-22 20:35:10 -0400
committerSimon Charette <charette.s@gmail.com>2016-05-26 13:32:02 -0400
commitdfae72f45a74b8fe3a08fe0a48c11bfeb9b9efda (patch)
tree0316b8a24cb7c97b7c654c74c7620821d90ca9aa
parent699e43b017b01ab2ef9f1e7a5a75c50a20956485 (diff)
[1.10.x] Fixed #26647 -- Included the state of all applied migrations when migrating forward.
Thanks Jasper Maes for the detailed report. Backport of 36d36818a30025034cad6f1ee59b2a960a6582ec from master
-rw-r--r--django/db/migrations/executor.py5
-rw-r--r--tests/migrations/migrations_test_apps/mutate_state_a/__init__.py0
-rw-r--r--tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py22
-rw-r--r--tests/migrations/migrations_test_apps/mutate_state_a/migrations/__init__.py0
-rw-r--r--tests/migrations/migrations_test_apps/mutate_state_b/__init__.py0
-rw-r--r--tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py21
-rw-r--r--tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py21
-rw-r--r--tests/migrations/migrations_test_apps/mutate_state_b/migrations/__init__.py0
-rw-r--r--tests/migrations/test_executor.py28
9 files changed, 95 insertions, 2 deletions
diff --git a/django/db/migrations/executor.py b/django/db/migrations/executor.py
index 4487543f16..fb9c7a93a4 100644
--- a/django/db/migrations/executor.py
+++ b/django/db/migrations/executor.py
@@ -116,8 +116,8 @@ class MigrationExecutor(object):
if key in self.loader.graph.nodes
}
for migration, _ in full_plan:
- if not migrations_to_run:
- # We remove every migration that we applied from this set so
+ if not migrations_to_run and not applied_migrations:
+ # We remove every migration that we applied from these sets so
# that we can bail out once the last migration has been applied
# and don't always run until the very end of the migration
# process.
@@ -136,6 +136,7 @@ class MigrationExecutor(object):
# to make sure the resulting state doesn't include changes
# from unrelated migrations.
migration.mutate_state(state, preserve=False)
+ applied_migrations.remove(migration)
return state
diff --git a/tests/migrations/migrations_test_apps/mutate_state_a/__init__.py b/tests/migrations/migrations_test_apps/mutate_state_a/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/migrations/migrations_test_apps/mutate_state_a/__init__.py
diff --git a/tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py
new file mode 100644
index 0000000000..5fac74abf3
--- /dev/null
+++ b/tests/migrations/migrations_test_apps/mutate_state_a/migrations/0001_initial.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('mutate_state_b', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.SeparateDatabaseAndState([], [
+ migrations.CreateModel(
+ name='A',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
+ ],
+ ),
+ ])
+ ]
diff --git a/tests/migrations/migrations_test_apps/mutate_state_a/migrations/__init__.py b/tests/migrations/migrations_test_apps/mutate_state_a/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/migrations/migrations_test_apps/mutate_state_a/migrations/__init__.py
diff --git a/tests/migrations/migrations_test_apps/mutate_state_b/__init__.py b/tests/migrations/migrations_test_apps/mutate_state_b/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/migrations/migrations_test_apps/mutate_state_b/__init__.py
diff --git a/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py
new file mode 100644
index 0000000000..73f436b20d
--- /dev/null
+++ b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0001_initial.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.SeparateDatabaseAndState([], [
+ migrations.CreateModel(
+ name='B',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
+ ],
+ ),
+ ])
+ ]
diff --git a/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py
new file mode 100644
index 0000000000..45aca30740
--- /dev/null
+++ b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/0002_add_field.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('mutate_state_b', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.SeparateDatabaseAndState([], [
+ migrations.AddField(
+ model_name='B',
+ name='added',
+ field=models.TextField(),
+ ),
+ ])
+ ]
diff --git a/tests/migrations/migrations_test_apps/mutate_state_b/migrations/__init__.py b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/migrations/migrations_test_apps/mutate_state_b/migrations/__init__.py
diff --git a/tests/migrations/test_executor.py b/tests/migrations/test_executor.py
index b51e7be90e..7c33c1be5c 100644
--- a/tests/migrations/test_executor.py
+++ b/tests/migrations/test_executor.py
@@ -477,6 +477,34 @@ class ExecutorTests(MigrationTestBase):
self.assertTableNotExists("lookuperror_b_b1")
self.assertTableNotExists("lookuperror_c_c1")
+ @override_settings(
+ INSTALLED_APPS=[
+ 'migrations.migrations_test_apps.mutate_state_a',
+ 'migrations.migrations_test_apps.mutate_state_b',
+ ]
+ )
+ def test_unrelated_applied_migrations_mutate_state(self):
+ """
+ #26647 - Unrelated applied migrations should be part of the final
+ state in both directions.
+ """
+ executor = MigrationExecutor(connection)
+ executor.migrate([
+ ('mutate_state_b', '0002_add_field'),
+ ])
+ # Migrate forward.
+ executor.loader.build_graph()
+ state = executor.migrate([
+ ('mutate_state_a', '0001_initial'),
+ ])
+ self.assertIn('added', dict(state.models['mutate_state_b', 'b'].fields))
+ executor.loader.build_graph()
+ # Migrate backward.
+ state = executor.migrate([
+ ('mutate_state_a', None),
+ ])
+ self.assertIn('added', dict(state.models['mutate_state_b', 'b'].fields))
+
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
def test_process_callback(self):
"""