diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py index 5f41053283..4bcbae8bd3 100644 --- a/django/db/migrations/autodetector.py +++ b/django/db/migrations/autodetector.py @@ -1022,8 +1022,9 @@ class MigrationAutodetector: def _generate_added_field(self, app_label, model_name, field_name): field = self.to_state.models[app_label, model_name].get_field(field_name) - # Fields that are foreignkeys/m2ms depend on stuff - dependencies = [] + # Adding a field always depends at least on its removal. + dependencies = [(app_label, model_name, field_name, False)] + # Fields that are foreignkeys/m2ms depend on stuff. if field.remote_field and field.remote_field.model: dependencies.extend( self._get_dependencies_for_foreign_key( diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py index 547e0b32c5..33411c9e3e 100644 --- a/tests/migrations/test_autodetector.py +++ b/tests/migrations/test_autodetector.py @@ -868,6 +868,18 @@ class AutodetectorTests(TestCase): "unique_together": {("title", "newfield2")}, }, ) + book_unique_together = ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ForeignKey("testapp.Author", models.CASCADE)), + ("title", models.CharField(max_length=200)), + ], + { + "unique_together": {("author", "title")}, + }, + ) attribution = ModelState( "otherapp", "Attribution", @@ -3798,16 +3810,16 @@ class AutodetectorTests(TestCase): # Right number/type of migrations? self.assertNumberMigrations(changes, "testapp", 1) self.assertOperationTypes( - changes, "testapp", 0, ["RemoveField", "AddField", "DeleteModel"] + changes, "testapp", 0, ["RemoveField", "DeleteModel", "AddField"] ) self.assertOperationAttributes( changes, "testapp", 0, 0, name="publishers", model_name="author" ) + self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher") self.assertOperationAttributes( - changes, "testapp", 0, 1, name="publishers", model_name="author" + changes, "testapp", 0, 2, name="publishers", model_name="author" ) - self.assertOperationAttributes(changes, "testapp", 0, 2, name="Publisher") - self.assertOperationFieldAttributes(changes, "testapp", 0, 1, max_length=100) + self.assertOperationFieldAttributes(changes, "testapp", 0, 2, max_length=100) def test_non_circular_foreignkey_dependency_removal(self): """ @@ -4346,6 +4358,36 @@ class AutodetectorTests(TestCase): changes, "testapp", 0, [("otherapp", "__first__")] ) + def test_alter_unique_together_fk_to_m2m(self): + changes = self.get_changes( + [self.author_name, self.book_unique_together], + [ + self.author_name, + ModelState( + "otherapp", + "Book", + [ + ("id", models.AutoField(primary_key=True)), + ("author", models.ManyToManyField("testapp.Author")), + ("title", models.CharField(max_length=200)), + ], + ), + ], + ) + self.assertNumberMigrations(changes, "otherapp", 1) + self.assertOperationTypes( + changes, "otherapp", 0, ["AlterUniqueTogether", "RemoveField", "AddField"] + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 0, name="book", unique_together=set() + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 1, model_name="book", name="author" + ) + self.assertOperationAttributes( + changes, "otherapp", 0, 2, model_name="book", name="author" + ) + def test_alter_field_to_fk_dependency_other_app(self): changes = self.get_changes( [self.author_empty, self.book_with_no_author_fk],