Fixed #31788 -- Fixed migration optimization after altering field to ManyToManyField.

This makes AddField() used for altering to ManyToManyField, dependent
on the prior RemoveField.
This commit is contained in:
David Wobrock 2022-06-02 12:10:27 +02:00 committed by GitHub
parent 6f73eb9d90
commit 798b6c23ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 6 deletions

View File

@ -1022,8 +1022,9 @@ class MigrationAutodetector:
def _generate_added_field(self, app_label, model_name, field_name): def _generate_added_field(self, app_label, model_name, field_name):
field = self.to_state.models[app_label, model_name].get_field(field_name) field = self.to_state.models[app_label, model_name].get_field(field_name)
# Fields that are foreignkeys/m2ms depend on stuff # Adding a field always depends at least on its removal.
dependencies = [] 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: if field.remote_field and field.remote_field.model:
dependencies.extend( dependencies.extend(
self._get_dependencies_for_foreign_key( self._get_dependencies_for_foreign_key(

View File

@ -868,6 +868,18 @@ class AutodetectorTests(TestCase):
"unique_together": {("title", "newfield2")}, "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( attribution = ModelState(
"otherapp", "otherapp",
"Attribution", "Attribution",
@ -3798,16 +3810,16 @@ class AutodetectorTests(TestCase):
# Right number/type of migrations? # Right number/type of migrations?
self.assertNumberMigrations(changes, "testapp", 1) self.assertNumberMigrations(changes, "testapp", 1)
self.assertOperationTypes( self.assertOperationTypes(
changes, "testapp", 0, ["RemoveField", "AddField", "DeleteModel"] changes, "testapp", 0, ["RemoveField", "DeleteModel", "AddField"]
) )
self.assertOperationAttributes( self.assertOperationAttributes(
changes, "testapp", 0, 0, name="publishers", model_name="author" changes, "testapp", 0, 0, name="publishers", model_name="author"
) )
self.assertOperationAttributes(changes, "testapp", 0, 1, name="Publisher")
self.assertOperationAttributes( 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, 2, max_length=100)
self.assertOperationFieldAttributes(changes, "testapp", 0, 1, max_length=100)
def test_non_circular_foreignkey_dependency_removal(self): def test_non_circular_foreignkey_dependency_removal(self):
""" """
@ -4346,6 +4358,36 @@ class AutodetectorTests(TestCase):
changes, "testapp", 0, [("otherapp", "__first__")] 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): def test_alter_field_to_fk_dependency_other_app(self):
changes = self.get_changes( changes = self.get_changes(
[self.author_empty, self.book_with_no_author_fk], [self.author_empty, self.book_with_no_author_fk],