Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix weird planning issues when already fully migrated.

  • Loading branch information...
commit b61b6346284fb32614aab965bd2cb09b383fc9f5 1 parent b4c493e
@andrewgodwin andrewgodwin authored
View
13 django/db/migrations/executor.py
@@ -33,10 +33,15 @@ def migration_plan(self, targets):
# If the migration is already applied, do backwards mode,
# otherwise do forwards mode.
elif target in applied:
- for migration in self.loader.graph.backwards_plan(target)[:-1]:
- if migration in applied:
- plan.append((self.loader.graph.nodes[migration], True))
- applied.remove(migration)
+ backwards_plan = self.loader.graph.backwards_plan(target)[:-1]
+ # We only do this if the migration is not the most recent one
+ # in its app - that is, another migration with the same app
+ # label is in the backwards plan
+ if any(node[0] == target[0] for node in backwards_plan):
+ for migration in backwards_plan:
+ if migration in applied:
+ plan.append((self.loader.graph.nodes[migration], True))
+ applied.remove(migration)
else:
for migration in self.loader.graph.forwards_plan(target):
if migration not in applied:
View
34 tests/migrations/test_executor.py
@@ -12,7 +12,7 @@ class ExecutorTests(TransactionTestCase):
test failures first, as they may be propagating into here.
"""
- available_apps = ["migrations"]
+ available_apps = ["migrations", "django.contrib.sessions"]
@override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations"})
def test_run(self):
@@ -38,3 +38,35 @@ def test_run(self):
# Are the tables there now?
self.assertIn("migrations_author", connection.introspection.get_table_list(connection.cursor()))
self.assertIn("migrations_book", connection.introspection.get_table_list(connection.cursor()))
+
+ @override_settings(MIGRATION_MODULES={"migrations": "migrations.test_migrations", "sessions": "migrations.test_migrations_2"})
+ def test_empty_plan(self):
+ """
+ Tests that re-planning a full migration of a fully-migrated set doesn't
+ perform spurious unmigrations and remigrations.
+
+ There was previously a bug where the executor just always performed the
+ backwards plan for applied migrations - which even for the most recent
+ migration in an app, might include other, dependent apps, and these
+ were being unmigrated.
+ """
+ # Make the initial plan, check it
+ # We use 'sessions' here as the second app as it's always present
+ # in INSTALLED_APPS, so we can happily assign it test migrations.
+ executor = MigrationExecutor(connection)
+ plan = executor.migration_plan([("migrations", "0002_second"), ("sessions", "0001_initial")])
+ self.assertEqual(
+ plan,
+ [
+ (executor.loader.graph.nodes["migrations", "0001_initial"], False),
+ (executor.loader.graph.nodes["migrations", "0002_second"], False),
+ (executor.loader.graph.nodes["sessions", "0001_initial"], False),
+ ],
+ )
+ # Fake-apply all migrations
+ executor.migrate([("migrations", "0002_second"), ("sessions", "0001_initial")], fake=True)
+ # Now plan a second time and make sure it's empty
+ plan = executor.migration_plan([("migrations", "0002_second"), ("sessions", "0001_initial")])
+ self.assertEqual(plan, [])
+ # Erase all the fake records
+ executor.recorder.flush()
View
21 tests/migrations/test_migrations_2/0001_initial.py
@@ -0,0 +1,21 @@
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [("migrations", "0002_second")]
+
+ operations = [
+
+ migrations.CreateModel(
+ "OtherAuthor",
+ [
+ ("id", models.AutoField(primary_key=True)),
+ ("name", models.CharField(max_length=255)),
+ ("slug", models.SlugField(null=True)),
+ ("age", models.IntegerField(default=0)),
+ ("silly_field", models.BooleanField(default=False)),
+ ],
+ ),
+
+ ]
View
0  tests/migrations/test_migrations_2/__init__.py
No changes.
Please sign in to comment.
Something went wrong with that request. Please try again.