summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmos Onn <amosonn@gmail.com>2015-12-08 19:03:31 +0200
committerTim Graham <timograham@gmail.com>2015-12-09 11:08:01 -0500
commitf076cf07effe54af8a28f22431c3c76a8af61fc5 (patch)
tree05006a0eaef69ece0fcdbbf04713355723c38f78
parentbc8bc8a0123b9a4c14beb62f71616a925538ca5c (diff)
[1.9.x] Fixed #25896 -- Fixed state bug in SeparateDatabaseAndState.database_backwards().
Backport of 542b7f6c50df18f2aa201cf1de81577c1bee643c from master
-rw-r--r--django/db/migrations/operations/special.py2
-rw-r--r--docs/releases/1.8.8.txt3
-rw-r--r--docs/releases/1.9.1.txt3
-rw-r--r--tests/migrations/test_operations.py76
4 files changed, 83 insertions, 1 deletions
diff --git a/django/db/migrations/operations/special.py b/django/db/migrations/operations/special.py
index e1ce9a07b5..6bbae602db 100644
--- a/django/db/migrations/operations/special.py
+++ b/django/db/migrations/operations/special.py
@@ -50,7 +50,7 @@ class SeparateDatabaseAndState(Operation):
to_state = base_state.clone()
for dbop in self.database_operations[:-(pos + 1)]:
dbop.state_forwards(app_label, to_state)
- from_state = base_state.clone()
+ from_state = to_state.clone()
database_operation.state_forwards(app_label, from_state)
database_operation.database_backwards(app_label, schema_editor, from_state, to_state)
diff --git a/docs/releases/1.8.8.txt b/docs/releases/1.8.8.txt
index bd6309b96e..3b86fefaea 100644
--- a/docs/releases/1.8.8.txt
+++ b/docs/releases/1.8.8.txt
@@ -27,3 +27,6 @@ Bugfixes
* Restored the ability to use custom formats from ``formats.py`` with
``django.utils.formats.get_format()`` and the ``date`` template filter
(:ticket:`25812`).
+
+* Fixed a state bug when migrating a ``SeparateDatabaseAndState`` operation
+ backwards (:ticket:`25896`).
diff --git a/docs/releases/1.9.1.txt b/docs/releases/1.9.1.txt
index f56c13e517..98569a14df 100644
--- a/docs/releases/1.9.1.txt
+++ b/docs/releases/1.9.1.txt
@@ -16,3 +16,6 @@ Bugfixes
(:ticket:`25548`).
* Fixed a system check crash with nested ``ArrayField``\s (:ticket:`25867`).
+
+* Fixed a state bug when migrating a ``SeparateDatabaseAndState`` operation
+ backwards (:ticket:`25896`).
diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py
index c8f1189b3c..7118996ff7 100644
--- a/tests/migrations/test_operations.py
+++ b/tests/migrations/test_operations.py
@@ -1850,6 +1850,82 @@ class OperationTests(OperationTestBase):
self.assertEqual(definition[1], [])
self.assertEqual(sorted(definition[2]), ["database_operations", "state_operations"])
+ def test_separate_database_and_state2(self):
+ """
+ A complex SeparateDatabaseAndState operation: Multiple operations both
+ for state and database. Verify the state dependencies within each list
+ and that state ops don't affect the database.
+ """
+ app_label = "test_separatedatabaseandstate2"
+ project_state = self.set_up_test_model(app_label)
+ # Create the operation
+ database_operations = [
+ migrations.CreateModel(
+ "ILovePonies",
+ [("id", models.AutoField(primary_key=True))],
+ options={"db_table": "iloveponies"},
+ ),
+ migrations.CreateModel(
+ "ILoveMorePonies",
+ [("id", models.AutoField(primary_key=True))],
+ options={"db_table": "ilovemoreponies"},
+ ),
+ migrations.DeleteModel("ILoveMorePonies"),
+ migrations.CreateModel(
+ "ILoveEvenMorePonies",
+ [("id", models.AutoField(primary_key=True))],
+ options={"db_table": "iloveevenmoreponies"},
+ ),
+ ]
+ state_operations = [
+ migrations.CreateModel(
+ "SomethingElse",
+ [("id", models.AutoField(primary_key=True))],
+ options={"db_table": "somethingelse"},
+ ),
+ migrations.DeleteModel("SomethingElse"),
+ migrations.CreateModel(
+ "SomethingCompletelyDifferent",
+ [("id", models.AutoField(primary_key=True))],
+ options={"db_table": "somethingcompletelydifferent"},
+ ),
+ ]
+ operation = migrations.SeparateDatabaseAndState(
+ state_operations=state_operations,
+ database_operations=database_operations,
+ )
+ # Test the state alteration
+ new_state = project_state.clone()
+ operation.state_forwards(app_label, new_state)
+
+ def assertModelsAndTables(after_db):
+ # Check that tables and models exist, or don't, as they should:
+ self.assertNotIn((app_label, "somethingelse"), new_state.models)
+ self.assertEqual(len(new_state.models[app_label, "somethingcompletelydifferent"].fields), 1)
+ self.assertNotIn((app_label, "iloveponiesonies"), new_state.models)
+ self.assertNotIn((app_label, "ilovemoreponies"), new_state.models)
+ self.assertNotIn((app_label, "iloveevenmoreponies"), new_state.models)
+ self.assertTableNotExists("somethingelse")
+ self.assertTableNotExists("somethingcompletelydifferent")
+ self.assertTableNotExists("ilovemoreponies")
+ if after_db:
+ self.assertTableExists("iloveponies")
+ self.assertTableExists("iloveevenmoreponies")
+ else:
+ self.assertTableNotExists("iloveponies")
+ self.assertTableNotExists("iloveevenmoreponies")
+
+ assertModelsAndTables(after_db=False)
+ # Test the database alteration
+ with connection.schema_editor() as editor:
+ operation.database_forwards(app_label, editor, project_state, new_state)
+ assertModelsAndTables(after_db=True)
+ # And test reversal
+ self.assertTrue(operation.reversible)
+ with connection.schema_editor() as editor:
+ operation.database_backwards(app_label, editor, new_state, project_state)
+ assertModelsAndTables(after_db=False)
+
class SwappableOperationTests(OperationTestBase):
"""