Example #1
0
    def test_proxy_ignorance(self):
        "Tests that the autodetector correctly ignores proxy models"
        # First, we test adding a proxy model
        before = self.make_project_state([self.author_empty])
        after = self.make_project_state([self.author_empty, self.author_proxy])
        autodetector = MigrationAutodetector(before, after)
        changes = autodetector._detect_changes()
        # Right number of migrations?
        self.assertEqual(len(changes), 0)

        # Now, we test turning a proxy model into a non-proxy model
        before = self.make_project_state(
            [self.author_empty, self.author_proxy])
        after = self.make_project_state(
            [self.author_empty, self.author_proxy_notproxy])
        autodetector = MigrationAutodetector(before, after)
        changes = autodetector._detect_changes()
        # Right number of migrations?
        self.assertEqual(len(changes['testapp']), 1)
        # Right number of actions?
        migration = changes['testapp'][0]
        self.assertEqual(len(migration.operations), 1)
        # Right action?
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "CreateModel")
        self.assertEqual(action.name, "AuthorProxy")
Example #2
0
def migrate_models(from_models, to_models):
    from_state = _get_state(from_models)
    to_state = _get_state(to_models)

    questioner = MigrationQuestioner()

    # Set up autodetector
    autodetector = MigrationAutodetector(from_state, to_state, questioner)

    graph = MigrationGraph()
    migrations = autodetector._detect_changes().get('indexing')
    if migrations:
        with connection.schema_editor() as schema_editor:
            for migration in migrations:
                for operation in migration.operations:
                    # Since migrations are not loaded from disk, migrations
                    # which contain fields will have their field bound to models.
                    # We need to recreate these fields as if they were loaded
                    # from disk. Thus deconstructing them and reconstructing.
                    # However Django has a shortcut for this 'clone()'.
                    if isinstance(operation, operations.CreateModel):
                        operation.fields = [
                            (field[0], field[1].clone())
                            for field in operation.fields
                        ]
                    elif isinstance(
                        operation, (
                            operations.AddField, operations.AlterField
                        )
                    ):
                        operation.field = operation.field.clone()

                    logger.info(operation.describe())
                migration.apply(from_state, schema_editor)
Example #3
0
 def test_arrange_for_graph(self):
     "Tests auto-naming of migrations for graph matching."
     # Make a fake graph
     graph = MigrationGraph()
     graph.add_node(("testapp", "0001_initial"), None)
     graph.add_node(("testapp", "0002_foobar"), None)
     graph.add_node(("otherapp", "0001_initial"), None)
     graph.add_dependency(("testapp", "0002_foobar"),
                          ("testapp", "0001_initial"))
     graph.add_dependency(("testapp", "0002_foobar"),
                          ("otherapp", "0001_initial"))
     # Use project state to make a new migration change set
     before = self.make_project_state([])
     after = self.make_project_state(
         [self.author_empty, self.other_pony, self.other_stable])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Run through arrange_for_graph
     changes = autodetector._arrange_for_graph(changes, graph)
     # Make sure there's a new name, deps match, etc.
     self.assertEqual(changes["testapp"][0].name, "0003_author")
     self.assertEqual(changes["testapp"][0].dependencies,
                      [("testapp", "0002_foobar")])
     self.assertEqual(changes["otherapp"][0].name, "0002_pony_stable")
     self.assertEqual(changes["otherapp"][0].dependencies,
                      [("otherapp", "0001_initial")])
Example #4
0
 def test_fk_dependency(self):
     "Tests that having a ForeignKey automatically adds a dependency"
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.author_name, self.book, self.edition])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     self.assertEqual(len(changes['otherapp']), 1)
     self.assertEqual(len(changes['thirdapp']), 1)
     # Right number of actions?
     migration1 = changes['testapp'][0]
     self.assertEqual(len(migration1.operations), 1)
     migration2 = changes['otherapp'][0]
     self.assertEqual(len(migration2.operations), 1)
     migration3 = changes['thirdapp'][0]
     self.assertEqual(len(migration3.operations), 1)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration3.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [])
     self.assertEqual(migration2.dependencies, [("testapp", "auto_1")])
     self.assertEqual(migration3.dependencies, [("otherapp", "auto_1")])
Example #5
0
 def test_same_app_circular_fk_dependency_and_unique_together(self):
     """
     Tests that a migration with circular FK dependency does not try to
     create unique together constraint before creating all required fields first.
     See ticket #22275.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.knight, self.rabbit])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['eggs']), 2)
     # Right number of actions?
     migration1 = changes['eggs'][0]
     self.assertEqual(len(migration1.operations), 2)
     migration2 = changes['eggs'][1]
     self.assertEqual(len(migration2.operations), 2)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration1.operations[1]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     # CreateModel action for Rabbit should not have unique_together now
     self.assertEqual(action.name, "Rabbit")
     self.assertFalse("unique_together" in action.options)
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "parent")
     action = migration2.operations[1]
     self.assertEqual(action.__class__.__name__, "AlterUniqueTogether")
     self.assertEqual(action.name, "rabbit")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [])
     self.assertEqual(migration2.dependencies, [("eggs", "auto_1")])
Example #6
0
 def test_fk_dependency(self):
     "Tests that having a ForeignKey automatically adds a dependency"
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state(
         [self.author_name, self.book, self.edition])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     self.assertEqual(len(changes['otherapp']), 1)
     self.assertEqual(len(changes['thirdapp']), 1)
     # Right number of actions?
     migration1 = changes['testapp'][0]
     self.assertEqual(len(migration1.operations), 1)
     migration2 = changes['otherapp'][0]
     self.assertEqual(len(migration2.operations), 1)
     migration3 = changes['thirdapp'][0]
     self.assertEqual(len(migration3.operations), 1)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration3.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [])
     self.assertEqual(migration2.dependencies, [("testapp", "auto_1")])
     self.assertEqual(migration3.dependencies, [("otherapp", "auto_1")])
Example #7
0
 def test_many_to_many_removed_before_through_model(self):
     """
     Removing a ManyToManyField and the "through" model in the same change must remove
     the field before the model to maintain consistency.
     """
     before = self.make_project_state([self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution])
     after = self.make_project_state([self.book_with_no_author, self.author_name])  # removes both the through model and ManyToMany
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['otherapp']), 1)
     # Right number of actions?
     migration = changes['otherapp'][0]
     self.assertEqual(len(migration.operations), 4)
     # Right actions in right order?
     # The first two are because we can't optimise RemoveField
     # into DeleteModel reliably.
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "RemoveField")
     self.assertEqual(action.name, "author")
     action = migration.operations[1]
     self.assertEqual(action.__class__.__name__, "RemoveField")
     self.assertEqual(action.name, "book")
     action = migration.operations[2]
     self.assertEqual(action.__class__.__name__, "RemoveField")
     self.assertEqual(action.name, "authors")
     action = migration.operations[3]
     self.assertEqual(action.__class__.__name__, "DeleteModel")
     self.assertEqual(action.name, "Attribution")
Example #8
0
 def test_same_app_circular_fk_dependency(self):
     """
     Tests that a migration with a FK between two models of the same app
     does not have a dependency to itself.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state(
         [self.author_with_publisher, self.publisher_with_author])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 2)
     # Right number of actions?
     migration1 = changes['testapp'][0]
     self.assertEqual(len(migration1.operations), 2)
     migration2 = changes['testapp'][1]
     self.assertEqual(len(migration2.operations), 1)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration1.operations[1]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "publisher")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [])
     self.assertEqual(migration2.dependencies, [("testapp", "auto_1")])
Example #9
0
 def test_circular_fk_dependency(self):
     """
     Tests that having a circular ForeignKey dependency automatically
     resolves the situation into 2 migrations on one side and 1 on the other.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.author_with_book, self.book])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     self.assertEqual(len(changes['otherapp']), 2)
     # Right number of actions?
     migration1 = changes['testapp'][0]
     self.assertEqual(len(migration1.operations), 1)
     migration2 = changes['otherapp'][0]
     self.assertEqual(len(migration2.operations), 1)
     migration3 = changes['otherapp'][1]
     self.assertEqual(len(migration2.operations), 1)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     self.assertEqual(len(action.fields), 2)
     action = migration3.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "author")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [("otherapp", "auto_1")])
     self.assertEqual(migration2.dependencies, [])
     self.assertEqual(set(migration3.dependencies),
                      set([("otherapp", "auto_1"), ("testapp", "auto_1")]))
Example #10
0
 def test_rename_model_with_renamed_rel_field(self):
     """
     Tests autodetection of renamed models while simultaneously renaming one
     of the fields that relate to the renamed model.
     """
     # Make state
     before = self.make_project_state([self.author_with_book, self.book])
     after = self.make_project_state([self.author_renamed_with_book, self.book_with_field_and_author_renamed])
     autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename_model": True, "ask_rename": True}))
     changes = autodetector._detect_changes()
     # Right number of migrations for model rename?
     self.assertNumberMigrations(changes, 'testapp', 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right actions?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "RenameModel")
     self.assertEqual(action.old_name, "Author")
     self.assertEqual(action.new_name, "Writer")
     # Right number of migrations for related field rename?
     # Alter is already taken care of.
     self.assertNumberMigrations(changes, 'otherapp', 1)
     # Right number of actions?
     migration = changes['otherapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right actions?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "RenameField")
     self.assertEqual(action.old_name, "author")
     self.assertEqual(action.new_name, "writer")
Example #11
0
 def test_same_app_no_fk_dependency(self):
     """
     Tests that a migration with a FK between two models of the same app
     does not have a dependency to itself.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.author_with_publisher, self.publisher])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 3)
     # Right actions?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration.operations[1]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     # Third action might vanish one day if the optimizer improves.
     action = migration.operations[2]
     self.assertEqual(action.__class__.__name__, "AddField")
     # Right dependencies?
     self.assertEqual(migration.dependencies, [])
Example #12
0
 def test_replace_string_with_foreignkey(self):
     """
     Adding an FK in the same "spot" as a deleted CharField should work. (#22300).
     """
     # Make state
     before = self.make_project_state([self.author_with_publisher_string])
     after = self.make_project_state(
         [self.author_with_publisher, self.publisher])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 3)
     # Right actions?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     self.assertEqual(action.name, "Publisher")
     action = migration.operations[1]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "publisher")
     action = migration.operations[2]
     self.assertEqual(action.__class__.__name__, "RemoveField")
     self.assertEqual(action.name, "publisher_name")
Example #13
0
 def test_same_app_circular_fk_dependency(self):
     """
     Tests that a migration with a FK between two models of the same app
     does not have a dependency to itself.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.author_with_publisher, self.publisher_with_author])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 2)
     # Right number of actions?
     migration1 = changes['testapp'][0]
     self.assertEqual(len(migration1.operations), 2)
     migration2 = changes['testapp'][1]
     self.assertEqual(len(migration2.operations), 1)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration1.operations[1]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "publisher")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [])
     self.assertEqual(migration2.dependencies, [("testapp", "auto_1")])
Example #14
0
 def test_many_to_many_removed_before_through_model(self):
     """
     Removing a ManyToManyField and the "through" model in the same change must remove
     the field before the model to maintain consistency.
     """
     before = self.make_project_state([
         self.book_with_multiple_authors_through_attribution,
         self.author_name, self.attribution
     ])
     after = self.make_project_state([
         self.book_with_no_author, self.author_name
     ])  # removes both the through model and ManyToMany
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['otherapp']), 1)
     # Right number of actions?
     migration = changes['otherapp'][0]
     self.assertEqual(len(migration.operations), 2)
     # Right actions in right order?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "RemoveField")
     self.assertEqual(action.name, "authors")
     action = migration.operations[1]
     self.assertEqual(action.__class__.__name__, "DeleteModel")
     self.assertEqual(action.name, "Attribution")
Example #15
0
 def test_circular_fk_dependency(self):
     """
     Tests that having a circular ForeignKey dependency automatically
     resolves the situation into 2 migrations on one side and 1 on the other.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.author_with_book, self.book])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     self.assertEqual(len(changes['otherapp']), 2)
     # Right number of actions?
     migration1 = changes['testapp'][0]
     self.assertEqual(len(migration1.operations), 1)
     migration2 = changes['otherapp'][0]
     self.assertEqual(len(migration2.operations), 1)
     migration3 = changes['otherapp'][1]
     self.assertEqual(len(migration2.operations), 1)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     self.assertEqual(len(action.fields), 2)
     action = migration3.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "author")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [("otherapp", "auto_1")])
     self.assertEqual(migration2.dependencies, [])
     self.assertEqual(set(migration3.dependencies), set([("otherapp", "auto_1"), ("testapp", "auto_1")]))
Example #16
0
    def test_rename_model(self):
        "Tests autodetection of renamed models"
        # Make state
        before = self.make_project_state([self.author_with_book, self.book])
        after = self.make_project_state([self.author_renamed_with_book, self.book_with_author_renamed])
        autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename_model": True}))
        changes = autodetector._detect_changes()

        # Right number of migrations for model rename?
        self.assertEqual(len(changes['testapp']), 1)
        # Right number of actions?
        migration = changes['testapp'][0]
        self.assertEqual(len(migration.operations), 1)
        # Right action?
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "RenameModel")
        self.assertEqual(action.old_name, "Author")
        self.assertEqual(action.new_name, "Writer")

        # Right number of migrations for related field rename?
        self.assertEqual(len(changes['otherapp']), 1)
        # Right number of actions?
        migration = changes['otherapp'][0]
        self.assertEqual(len(migration.operations), 1)
        # Right action?
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "AlterField")
        self.assertEqual(action.name, "author")
        self.assertEqual(action.field.rel.to.__name__, "Writer")
Example #17
0
    def test_rename_model(self):
        "Tests autodetection of renamed models"
        # Make state
        before = self.make_project_state([self.author_with_book, self.book])
        after = self.make_project_state(
            [self.author_renamed_with_book, self.book_with_author_renamed])
        autodetector = MigrationAutodetector(
            before, after, MigrationQuestioner({"ask_rename_model": True}))
        changes = autodetector._detect_changes()

        # Right number of migrations for model rename?
        self.assertEqual(len(changes['testapp']), 1)
        # Right number of actions?
        migration = changes['testapp'][0]
        self.assertEqual(len(migration.operations), 1)
        # Right action?
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "RenameModel")
        self.assertEqual(action.old_name, "Author")
        self.assertEqual(action.new_name, "Writer")

        # Right number of migrations for related field rename?
        self.assertEqual(len(changes['otherapp']), 1)
        # Right number of actions?
        migration = changes['otherapp'][0]
        self.assertEqual(len(migration.operations), 1)
        # Right action?
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "AlterField")
        self.assertEqual(action.name, "author")
        self.assertEqual(action.field.rel.to, "testapp.Writer")
Example #18
0
 def test_same_app_circular_fk_dependency_and_unique_together(self):
     """
     Tests that a migration with circular FK dependency does not try to
     create unique together constraint before creating all required fields first.
     See ticket #22275.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.knight, self.rabbit])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['eggs']), 2)
     # Right number of actions?
     migration1 = changes['eggs'][0]
     self.assertEqual(len(migration1.operations), 2)
     migration2 = changes['eggs'][1]
     self.assertEqual(len(migration2.operations), 2)
     # Right actions?
     action = migration1.operations[0]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     action = migration1.operations[1]
     self.assertEqual(action.__class__.__name__, "CreateModel")
     # CreateModel action for Rabbit should not have unique_together now
     self.assertEqual(action.name, "Rabbit")
     self.assertFalse("unique_together" in action.options)
     action = migration2.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "parent")
     action = migration2.operations[1]
     self.assertEqual(action.__class__.__name__, "AlterUniqueTogether")
     self.assertEqual(action.name, "rabbit")
     # Right dependencies?
     self.assertEqual(migration1.dependencies, [])
     self.assertEqual(migration2.dependencies, [("eggs", "auto_1")])
Example #19
0
 def test_deconstruct_field_kwarg(self):
     """
     Field instances are handled correctly by nested deconstruction.
     """
     before = self.make_project_state([self.author_name_deconstructable_3])
     after = self.make_project_state([self.author_name_deconstructable_4])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     self.assertEqual(changes, {})
Example #20
0
 def test_deconstruct_field_kwarg(self):
     """
     Field instances are handled correctly by nested deconstruction.
     """
     before = self.make_project_state([self.author_name_deconstructable_3])
     after = self.make_project_state([self.author_name_deconstructable_4])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     self.assertEqual(changes, {})
Example #21
0
 def test_swappable(self):
     before = self.make_project_state([self.custom_user])
     after = self.make_project_state([self.custom_user, self.author_with_custom_user])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes), 1)
     # Check the dependency is correct
     migration = changes['testapp'][0]
     self.assertEqual(migration.dependencies, [("__setting__", "AUTH_USER_MODEL")])
Example #22
0
 def test_custom_deconstructable(self):
     """
     Two instances which deconstruct to the same value aren't considered a
     change.
     """
     before = self.make_project_state([self.author_name_deconstructable_1])
     after = self.make_project_state([self.author_name_deconstructable_2])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     self.assertEqual(changes, {})
Example #23
0
 def test_custom_deconstructable(self):
     """
     Two instances which deconstruct to the same value aren't considered a
     change.
     """
     before = self.make_project_state([self.author_name_deconstructable_1])
     after = self.make_project_state([self.author_name_deconstructable_2])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     self.assertEqual(changes, {})
 def test_set_alter_order_with_respect_to(self):
     "Tests that setting order_with_respect_to adds a field"
     # Make state
     before = self.make_project_state([self.book, self.author_with_book])
     after = self.make_project_state([self.book, self.author_with_book_order_wrt])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, 'testapp', 1)
     self.assertOperationTypes(changes, 'testapp', 0, ["AlterOrderWithRespectTo"])
     self.assertOperationAttributes(changes, 'testapp', 0, 0, name="author", order_with_respect_to="book")
 def test_alter_model_options_proxy(self):
     """
     Changing a proxy model's options should also make a change
     """
     before = self.make_project_state([self.author_proxy, self.author_empty])
     after = self.make_project_state([self.author_proxy_options, self.author_empty])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, "testapp", 1)
     # Right actions in right order?
     self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"])
 def test_create_with_through_model(self):
     """
     Adding a m2m with a through model and the models that use it should
     be ordered correctly.
     """
     before = self.make_project_state([])
     after = self.make_project_state([self.author_with_m2m_through, self.publisher, self.contract])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, "testapp", 1)
     # Right actions in right order?
     self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "CreateModel", "CreateModel", "AddField", "AddField"])
 def test_create_with_through_model(self):
     """
     Adding a m2m with a through model and the models that use it should
     be ordered correctly.
     """
     before = self.make_project_state([])
     after = self.make_project_state([self.author_with_m2m_through, self.publisher, self.contract])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, "testapp", 1)
     # Right actions in right order?
     self.assertOperationTypes(changes, "testapp", 0, ["CreateModel", "CreateModel", "CreateModel", "AddField", "AddField"])
 def test_alter_model_options(self):
     """
     If two models with a ForeignKey from one to the other are removed at the same time,
     the autodetector should remove them in the correct order.
     """
     before = self.make_project_state([self.author_empty])
     after = self.make_project_state([self.author_with_options])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, "testapp", 1)
     # Right actions in right order?
     self.assertOperationTypes(changes, "testapp", 0, ["AlterModelOptions"])
Example #29
0
 def test_non_circular_foreignkey_dependency_removal(self):
     """
     If two models with a ForeignKey from one to the other are removed at the same time,
     the autodetector should remove them in the correct order.
     """
     before = self.make_project_state([self.author_with_publisher, self.publisher_with_author])
     after = self.make_project_state([])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, "testapp", 1)
     # Right actions in right order?
     self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "RemoveField", "DeleteModel", "DeleteModel"])
 def test_many_to_many_removed_before_through_model_2(self):
     """
     Removing a model that contains a ManyToManyField and the
     "through" model in the same change must remove
     the field before the model to maintain consistency.
     """
     before = self.make_project_state([self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution])
     after = self.make_project_state([self.author_name])  # removes both the through model and ManyToMany
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, 'otherapp', 1)
     # Right number of actions?
     self.assertOperationTypes(changes, 'otherapp', 0, ["RemoveField", "RemoveField", "RemoveField", "DeleteModel", "DeleteModel"])
    def test_proxy(self):
        "Tests that the autodetector correctly deals with proxy models"
        # First, we test adding a proxy model
        before = self.make_project_state([self.author_empty])
        after = self.make_project_state([self.author_empty, self.author_proxy])
        autodetector = MigrationAutodetector(before, after)
        changes = autodetector._detect_changes()
        # Right number of migrations?
        self.assertNumberMigrations(changes, "testapp", 1)
        self.assertOperationTypes(changes, "testapp", 0, ["CreateModel"])
        self.assertOperationAttributes(changes, "testapp", 0, 0, name="AuthorProxy", options={"proxy": True})

        # Now, we test turning a proxy model into a non-proxy model
        # It should delete the proxy then make the real one
        before = self.make_project_state([self.author_empty, self.author_proxy])
        after = self.make_project_state([self.author_empty, self.author_proxy_notproxy])
        autodetector = MigrationAutodetector(before, after)
        changes = autodetector._detect_changes()
        # Right number of migrations?
        self.assertNumberMigrations(changes, "testapp", 1)
        self.assertOperationTypes(changes, "testapp", 0, ["DeleteModel", "CreateModel"])
        self.assertOperationAttributes(changes, "testapp", 0, 0, name="AuthorProxy")
        self.assertOperationAttributes(changes, "testapp", 0, 1, name="AuthorProxy", options={})
Example #32
0
    def test_proxy_ignorance(self):
        "Tests that the autodetector correctly ignores proxy models"
        # First, we test adding a proxy model
        before = self.make_project_state([self.author_empty])
        after = self.make_project_state([self.author_empty, self.author_proxy])
        autodetector = MigrationAutodetector(before, after)
        changes = autodetector._detect_changes()
        # Right number of migrations?
        self.assertEqual(len(changes), 0)

        # Now, we test turning a proxy model into a non-proxy model
        before = self.make_project_state([self.author_empty, self.author_proxy])
        after = self.make_project_state([self.author_empty, self.author_proxy_notproxy])
        autodetector = MigrationAutodetector(before, after)
        changes = autodetector._detect_changes()
        # Right number of migrations?
        self.assertEqual(len(changes['testapp']), 1)
        # Right number of actions?
        migration = changes['testapp'][0]
        self.assertEqual(len(migration.operations), 1)
        # Right action?
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "CreateModel")
        self.assertEqual(action.name, "AuthorProxy")
 def test_remove_alter_order_with_respect_to(self):
     """
     Tests that removing order_with_respect_to when removing the FK too
     does things in the right order.
     """
     # Make state
     before = self.make_project_state([self.book, self.author_with_book_order_wrt])
     after = self.make_project_state([self.author_name])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, 'testapp', 1)
     self.assertOperationTypes(changes, 'testapp', 0, ["AlterOrderWithRespectTo", "RemoveField"])
     self.assertOperationAttributes(changes, 'testapp', 0, 0, name="author", order_with_respect_to=None)
     self.assertOperationAttributes(changes, 'testapp', 0, 1, model_name="author", name="book")
Example #34
0
 def test_old_model(self):
     "Tests deletion of old models"
     # Make state
     before = self.make_project_state([self.author_empty])
     after = self.make_project_state([])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "DeleteModel")
     self.assertEqual(action.name, "Author")
Example #35
0
 def test_alter_field(self):
     "Tests autodetection of new fields"
     # Make state
     before = self.make_project_state([self.author_name])
     after = self.make_project_state([self.author_name_longer])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "AlterField")
     self.assertEqual(action.name, "name")
Example #36
0
 def test_old_model(self):
     "Tests deletion of old models"
     # Make state
     before = self.make_project_state([self.author_empty])
     after = self.make_project_state([])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "DeleteModel")
     self.assertEqual(action.name, "Author")
Example #37
0
 def test_trim_apps(self):
     "Tests that trim does not remove dependencies but does remove unwanted apps"
     # Use project state to make a new migration change set
     before = self.make_project_state([])
     after = self.make_project_state([self.author_empty, self.other_pony, self.other_stable, self.third_thing])
     autodetector = MigrationAutodetector(before, after, MigrationQuestioner(defaults={"ask_initial": True}))
     changes = autodetector._detect_changes()
     # Run through arrange_for_graph
     graph = MigrationGraph()
     changes = autodetector.arrange_for_graph(changes, graph)
     changes["testapp"][0].dependencies.append(("otherapp", "0001_initial"))
     changes = autodetector._trim_to_apps(changes, set(["testapp"]))
     # Make sure there's the right set of migrations
     self.assertEqual(changes["testapp"][0].name, "0001_initial")
     self.assertEqual(changes["otherapp"][0].name, "0001_initial")
     self.assertNotIn("thirdapp", changes)
Example #38
0
 def test_alter_field(self):
     "Tests autodetection of new fields"
     # Make state
     before = self.make_project_state([self.author_name])
     after = self.make_project_state([self.author_name_longer])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "AlterField")
     self.assertEqual(action.name, "name")
 def test_add_model_order_with_respect_to(self):
     """
     Tests that setting order_with_respect_to when adding the whole model
     does things in the right order.
     """
     # Make state
     before = self.make_project_state([])
     after = self.make_project_state([self.book, self.author_with_book_order_wrt])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, 'testapp', 1)
     self.assertOperationTypes(changes, 'testapp', 0, ["CreateModel", "AlterOrderWithRespectTo"])
     self.assertOperationAttributes(changes, 'testapp', 0, 1, name="author", order_with_respect_to="book")
     # Make sure the _order field is not in the CreateModel fields
     self.assertNotIn("_order", [name for name, field in changes['testapp'][0].operations[0].fields])
Example #40
0
 def test_rename_field(self):
     "Tests autodetection of renamed fields"
     # Make state
     before = self.make_project_state([self.author_name])
     after = self.make_project_state([self.author_name_renamed])
     autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename": True}))
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "RenameField")
     self.assertEqual(action.old_name, "name")
     self.assertEqual(action.new_name, "names")
Example #41
0
 def test_unique_together_ordering(self):
     "Tests that unique_together also triggers on ordering changes"
     # Make state
     before = self.make_project_state([self.author_empty, self.book_unique])
     after = self.make_project_state([self.author_empty, self.book_unique_2])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['otherapp']), 1)
     # Right number of actions?
     migration = changes['otherapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "AlterUniqueTogether")
     self.assertEqual(action.name, "book")
     self.assertEqual(action.unique_together, set([("title", "author")]))
Example #42
0
    def make_migrations(self):
        """Runs the auto-detector and detects changes in
        the project that can be put in a migration."""

        new_project_state = ProjectState.from_apps(self.apps)

        autodetector = MigrationAutodetector(self.project_state,
                                             new_project_state)

        changes = autodetector._detect_changes()
        migrations = changes.get('tests', [])
        migration = migrations[0] if len(migrations) > 0 else None

        self.migrations.append(migration)

        self.project_state = new_project_state
        return migration
Example #43
0
 def test_add_field_and_unique_together(self):
     "Tests that added fields will be created before using them in unique together"
     before = self.make_project_state([self.author_empty, self.book])
     after = self.make_project_state([self.author_empty, self.book_unique_3])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['otherapp']), 1)
     # Right number of actions?
     migration = changes['otherapp'][0]
     self.assertEqual(len(migration.operations), 2)
     # Right actions order?
     action1 = migration.operations[0]
     action2 = migration.operations[1]
     self.assertEqual(action1.__class__.__name__, "AddField")
     self.assertEqual(action2.__class__.__name__, "AlterUniqueTogether")
     self.assertEqual(action2.unique_together, set([("title", "newfield")]))
Example #44
0
 def test_unique_together(self):
     "Tests unique_together detection"
     # Make state
     before = self.make_project_state([self.author_empty, self.book])
     after = self.make_project_state([self.author_empty, self.book_unique])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['otherapp']), 1)
     # Right number of actions?
     migration = changes['otherapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "AlterUniqueTogether")
     self.assertEqual(action.name, "book")
     self.assertEqual(action.unique_together, set([("author", "title")]))
Example #45
0
 def test_add_field_and_unique_together(self):
     "Tests that added fields will be created before using them in unique together"
     before = self.make_project_state([self.author_empty, self.book])
     after = self.make_project_state([self.author_empty, self.book_unique_3])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['otherapp']), 1)
     # Right number of actions?
     migration = changes['otherapp'][0]
     self.assertEqual(len(migration.operations), 2)
     # Right actions order?
     action1 = migration.operations[0]
     action2 = migration.operations[1]
     self.assertEqual(action1.__class__.__name__, "AddField")
     self.assertEqual(action2.__class__.__name__, "AlterUniqueTogether")
     self.assertEqual(action2.unique_together, set([("title", "newfield")]))
Example #46
0
 def test_add_field_with_default(self):
     """
     Adding a field with a default should work (#22030).
     """
     # Make state
     before = self.make_project_state([self.author_empty])
     after = self.make_project_state([self.author_name_default])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "name")
Example #47
0
 def test_add_field_with_default(self):
     """
     Adding a field with a default should work (#22030).
     """
     # Make state
     before = self.make_project_state([self.author_empty])
     after = self.make_project_state([self.author_name_default])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 1)
     # Right action?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "AddField")
     self.assertEqual(action.name, "name")
Example #48
0
 def test_m2m_w_through_multistep_remove(self):
     """
     A model with a m2m field that specifies a "through" model cannot be removed in the same
     migration as that through model as the schema will pass through an inconsistent state.
     The autodetector should produce two migrations to avoid this issue.
     """
     before = self.make_project_state([self.author_with_m2m_through, self.publisher, self.contract])
     after = self.make_project_state([self.publisher])
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertNumberMigrations(changes, "testapp", 1)
     # Right actions in right order?
     self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "RemoveField", "DeleteModel", "RemoveField", "DeleteModel"])
     # Actions touching the right stuff?
     self.assertOperationAttributes(changes, "testapp", 0, 0, name="publishers")
     self.assertOperationAttributes(changes, "testapp", 0, 1, name="author")
     self.assertOperationAttributes(changes, "testapp", 0, 2, name="Author")
     self.assertOperationAttributes(changes, "testapp", 0, 3, name="publisher")
     self.assertOperationAttributes(changes, "testapp", 0, 4, name="Contract")
Example #49
0
    def test_rename_model(self):
        "Tests autodetection of renamed models"
        # Make state
        before = self.make_project_state([self.author_with_book, self.book])
        after = self.make_project_state([self.author_renamed_with_book, self.book_with_author_renamed])
        autodetector = MigrationAutodetector(before, after, MigrationQuestioner({"ask_rename_model": True}))
        changes = autodetector._detect_changes()

        # Right number of migrations for model rename?
        self.assertNumberMigrations(changes, 'testapp', 1)
        # Right number of actions?
        migration = changes['testapp'][0]
        self.assertEqual(len(migration.operations), 1)
        # Right action?
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "RenameModel")
        self.assertEqual(action.old_name, "Author")
        self.assertEqual(action.new_name, "Writer")
        # Now that RenameModel handles related fields too, there should be
        # no AlterField for the related field.
        self.assertNumberMigrations(changes, 'otherapp', 0)
Example #50
0
 def test_foreign_key_removed_before_target_model(self):
     """
     Removing an FK and the model it targets in the same change must remove
     the FK field before the model to maintain consistency.
     """
     before = self.make_project_state([self.author_with_publisher, self.publisher])
     after = self.make_project_state([self.author_name])  # removes both the model and FK
     autodetector = MigrationAutodetector(before, after)
     changes = autodetector._detect_changes()
     # Right number of migrations?
     self.assertEqual(len(changes['testapp']), 1)
     # Right number of actions?
     migration = changes['testapp'][0]
     self.assertEqual(len(migration.operations), 2)
     # Right actions in right order?
     action = migration.operations[0]
     self.assertEqual(action.__class__.__name__, "RemoveField")
     self.assertEqual(action.name, "publisher")
     action = migration.operations[1]
     self.assertEqual(action.__class__.__name__, "DeleteModel")
     self.assertEqual(action.name, "Publisher")
Example #51
0
    def test_add_many_to_many(self):
        """
        Adding a ManyToManyField should not prompt for a default (#22435).
        """
        class CustomQuestioner(MigrationQuestioner):
            def ask_not_null_addition(self, field_name, model_name):
                raise Exception("Should not have prompted for not null addition")

        before = self.make_project_state([self.author_empty, self.publisher])
        # Add ManyToManyField to author model
        after = self.make_project_state([self.author_with_m2m, self.publisher])
        autodetector = MigrationAutodetector(before, after, CustomQuestioner())
        changes = autodetector._detect_changes()
        # Right number of migrations?
        self.assertEqual(len(changes['testapp']), 1)
        migration = changes['testapp'][0]
        # Right actions in right order?
        self.assertEqual(len(migration.operations), 1)
        action = migration.operations[0]
        self.assertEqual(action.__class__.__name__, "AddField")
        self.assertEqual(action.name, "publishers")