[4.1.x] Fixed #31788 -- Fixed migration optimization after altering field to ManyToManyField.

This makes AddField() used for altering to ManyToManyField, dependent
on the prior RemoveField.
Backport of 798b6c23ee from main
This commit is contained in:
David Wobrock 2022-06-02 12:10:27 +02:00 committed by Mariusz Felisiak
parent 0fb0355271
commit 9fce76a237
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):
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(

View File

@ -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],