summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/migrations/autodetector.py5
-rw-r--r--tests/migrations/test_autodetector.py47
2 files changed, 51 insertions, 1 deletions
diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
index 7cc22c0637..0c2e215fcd 100644
--- a/django/db/migrations/autodetector.py
+++ b/django/db/migrations/autodetector.py
@@ -1339,7 +1339,10 @@ class MigrationAutodetector:
if old_field_dec != new_field_dec and old_field_name == field_name:
both_m2m = old_field.many_to_many and new_field.many_to_many
neither_m2m = not old_field.many_to_many and not new_field.many_to_many
- if both_m2m or neither_m2m:
+ target_changed = (
+ both_m2m and new_field_dec[2]["to"] != old_field_dec[2]["to"]
+ )
+ if (both_m2m or neither_m2m) and not target_changed:
# Either both fields are m2m or neither is
preserve_default = True
if (
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py
index c044cc9a99..e333621855 100644
--- a/tests/migrations/test_autodetector.py
+++ b/tests/migrations/test_autodetector.py
@@ -741,6 +741,13 @@ class AutodetectorTests(BaseAutodetectorTests):
("publishers", models.ManyToManyField("testapp.Publisher", blank=True)),
],
)
+ other_publisher = ModelState(
+ "testapp",
+ "OtherPublisher",
+ [
+ ("id", models.AutoField(primary_key=True)),
+ ],
+ )
author_with_m2m_through = ModelState(
"testapp",
"Author",
@@ -4557,6 +4564,46 @@ class AutodetectorTests(BaseAutodetectorTests):
)
self.assertOperationFieldAttributes(changes, "testapp", 0, 2, max_length=100)
+ def test_m2m_target_change_generates_remove_and_add(self):
+ before = [
+ self.publisher,
+ self.other_publisher,
+ self.author_with_m2m, # m2m to self.publisher.
+ ]
+
+ after = [
+ self.publisher,
+ self.other_publisher,
+ ModelState(
+ "testapp",
+ "Author",
+ [
+ ("id", models.AutoField(primary_key=True)),
+ # Repoint m2m to self.other_publisher.
+ ("publishers", models.ManyToManyField("testapp.OtherPublisher")),
+ ],
+ ),
+ ]
+ changes = self.get_changes(before, after)
+ self.assertNumberMigrations(changes, "testapp", 1)
+ self.assertOperationTypes(changes, "testapp", 0, ["RemoveField", "AddField"])
+ self.assertOperationAttributes(
+ changes,
+ "testapp",
+ 0,
+ 0,
+ name="publishers",
+ model_name="author",
+ )
+ self.assertOperationAttributes(
+ changes,
+ "testapp",
+ 0,
+ 1,
+ name="publishers",
+ model_name="author",
+ )
+
def test_non_circular_foreignkey_dependency_removal(self):
"""
If two models with a ForeignKey from one to the other are removed at