Browse Source

Fixed #34250 -- Fixed renaming model with m2m relation to a model with the same name.

DevilsAutumn 2 years ago
parent
commit
ff3a283422
2 changed files with 75 additions and 14 deletions
  1. 6 14
      django/db/migrations/operations/models.py
  2. 69 0
      tests/migrations/test_operations.py

+ 6 - 14
django/db/migrations/operations/models.py

@@ -407,20 +407,12 @@ class RenameModel(ModelOperation):
                     or not new_field.remote_field.through._meta.auto_created
                 ):
                     continue
-                # Rename the M2M table that's based on this model's name.
-                old_m2m_model = old_field.remote_field.through
-                new_m2m_model = new_field.remote_field.through
-                schema_editor.alter_db_table(
-                    new_m2m_model,
-                    old_m2m_model._meta.db_table,
-                    new_m2m_model._meta.db_table,
-                )
-                # Rename the column in the M2M table that's based on this
-                # model's name.
-                schema_editor.alter_field(
-                    new_m2m_model,
-                    old_m2m_model._meta.get_field(old_model._meta.model_name),
-                    new_m2m_model._meta.get_field(new_model._meta.model_name),
+                # Rename columns and the M2M table.
+                schema_editor._alter_many_to_many(
+                    new_model,
+                    old_field,
+                    new_field,
+                    strict=False,
                 )
 
     def database_backwards(self, app_label, schema_editor, from_state, to_state):

+ 69 - 0
tests/migrations/test_operations.py

@@ -1058,6 +1058,75 @@ class OperationTests(OperationTestBase):
             Pony._meta.get_field("riders").remote_field.through.objects.count(), 2
         )
 
+    def test_rename_model_with_m2m_models_in_different_apps_with_same_name(self):
+        app_label_1 = "test_rmw_m2m_1"
+        app_label_2 = "test_rmw_m2m_2"
+        project_state = self.apply_operations(
+            app_label_1,
+            ProjectState(),
+            operations=[
+                migrations.CreateModel(
+                    "Rider",
+                    fields=[
+                        ("id", models.AutoField(primary_key=True)),
+                    ],
+                ),
+            ],
+        )
+        project_state = self.apply_operations(
+            app_label_2,
+            project_state,
+            operations=[
+                migrations.CreateModel(
+                    "Rider",
+                    fields=[
+                        ("id", models.AutoField(primary_key=True)),
+                        ("riders", models.ManyToManyField(f"{app_label_1}.Rider")),
+                    ],
+                ),
+            ],
+        )
+        m2m_table = f"{app_label_2}_rider_riders"
+        self.assertColumnExists(m2m_table, "from_rider_id")
+        self.assertColumnExists(m2m_table, "to_rider_id")
+
+        Rider_1 = project_state.apps.get_model(app_label_1, "Rider")
+        Rider_2 = project_state.apps.get_model(app_label_2, "Rider")
+        rider_2 = Rider_2.objects.create()
+        rider_2.riders.add(Rider_1.objects.create())
+        # Rename model.
+        project_state_2 = project_state.clone()
+        project_state = self.apply_operations(
+            app_label_2,
+            project_state,
+            operations=[migrations.RenameModel("Rider", "Pony")],
+            atomic=connection.features.supports_atomic_references_rename,
+        )
+
+        m2m_table = f"{app_label_2}_pony_riders"
+        self.assertColumnExists(m2m_table, "pony_id")
+        self.assertColumnExists(m2m_table, "rider_id")
+
+        Rider_1 = project_state.apps.get_model(app_label_1, "Rider")
+        Rider_2 = project_state.apps.get_model(app_label_2, "Pony")
+        rider_2 = Rider_2.objects.create()
+        rider_2.riders.add(Rider_1.objects.create())
+        self.assertEqual(Rider_1.objects.count(), 2)
+        self.assertEqual(Rider_2.objects.count(), 2)
+        self.assertEqual(
+            Rider_2._meta.get_field("riders").remote_field.through.objects.count(), 2
+        )
+        # Reversal.
+        self.unapply_operations(
+            app_label_2,
+            project_state_2,
+            operations=[migrations.RenameModel("Rider", "Pony")],
+            atomic=connection.features.supports_atomic_references_rename,
+        )
+        m2m_table = f"{app_label_2}_rider_riders"
+        self.assertColumnExists(m2m_table, "to_rider_id")
+        self.assertColumnExists(m2m_table, "from_rider_id")
+
     def test_rename_model_with_db_table_rename_m2m(self):
         app_label = "test_rmwdbrm2m"
         project_state = self.apply_operations(