Commit 542b7f6c authored by Amos Onn's avatar Amos Onn Committed by Tim Graham
Browse files

Fixed #25896 -- Fixed state bug in SeparateDatabaseAndState.database_backwards().

parent 890938e7
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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)

+3 −0
Original line number Diff line number Diff line
@@ -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`).
+3 −0
Original line number Diff line number Diff line
@@ -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`).
+76 −0
Original line number Diff line number Diff line
@@ -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):
    """