summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/db/migrations/operations/models.py4
-rw-r--r--docs/releases/1.7.7.txt4
-rw-r--r--tests/migrations/test_operations.py35
3 files changed, 42 insertions, 1 deletions
diff --git a/django/db/migrations/operations/models.py b/django/db/migrations/operations/models.py
index 3d92b68c65..190d117503 100644
--- a/django/db/migrations/operations/models.py
+++ b/django/db/migrations/operations/models.py
@@ -122,6 +122,10 @@ class RenameModel(Operation):
del state.models[app_label, self.old_name.lower()]
# Repoint the FKs and M2Ms pointing to us
for related_object in (related_objects + related_m2m_objects):
+ if related_object.field.rel.to is not model:
+ # The model being renamed does not participate in this relation
+ # directly. Rather, a superclass does.
+ continue
# Use the new related key for self referential related objects.
if related_object.model == model:
related_key = (app_label, self.new_name.lower())
diff --git a/docs/releases/1.7.7.txt b/docs/releases/1.7.7.txt
index fa67c97de9..1c6b9325f4 100644
--- a/docs/releases/1.7.7.txt
+++ b/docs/releases/1.7.7.txt
@@ -9,4 +9,6 @@ Django 1.7.7 fixes several bugs in 1.7.6.
Bugfixes
========
-* ...
+* Fixed renaming of classes in migrations where renaming a subclass would
+ cause incorrect state to be recorded for objects that referenced the
+ superclass (:ticket:`24354`).
diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py
index 06a22d0f37..3cc225632a 100644
--- a/tests/migrations/test_operations.py
+++ b/tests/migrations/test_operations.py
@@ -482,6 +482,41 @@ class OperationTests(OperationTestBase):
self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id"))
self.assertFKNotExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
+ def test_rename_model_with_superclass_fk(self):
+ """
+ Tests the RenameModel operation on a model which has a superclass that
+ has a foreign key.
+ """
+ project_state = self.set_up_test_model("test_rmwsc", related_model=True, mti_model=True)
+ # Test the state alteration
+ operation = migrations.RenameModel("ShetlandPony", "LittleHorse")
+ self.assertEqual(operation.describe(), "Rename model ShetlandPony to LittleHorse")
+ new_state = project_state.clone()
+ operation.state_forwards("test_rmwsc", new_state)
+ self.assertNotIn(("test_rmwsc", "shetlandpony"), new_state.models)
+ self.assertIn(("test_rmwsc", "littlehorse"), new_state.models)
+ # RenameModel shouldn't repoint the superclass's relations, only local ones
+ self.assertEqual(
+ project_state.models["test_rmwsc", "rider"].fields[1][1].rel.to,
+ new_state.models["test_rmwsc", "rider"].fields[1][1].rel.to
+ )
+ # Before running the migration we have a table for Shetland Pony, not Little Horse
+ self.assertTableExists("test_rmwsc_shetlandpony")
+ self.assertTableNotExists("test_rmwsc_littlehorse")
+ if connection.features.supports_foreign_keys:
+ # and the foreign key on rider points to pony, not shetland pony
+ self.assertFKExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_pony", "id"))
+ self.assertFKNotExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_shetlandpony", "id"))
+ with connection.schema_editor() as editor:
+ operation.database_forwards("test_rmwsc", editor, project_state, new_state)
+ # Now we have a little horse table, not shetland pony
+ self.assertTableNotExists("test_rmwsc_shetlandpony")
+ self.assertTableExists("test_rmwsc_littlehorse")
+ if connection.features.supports_foreign_keys:
+ # but the Foreign keys still point at pony, not little horse
+ self.assertFKExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_pony", "id"))
+ self.assertFKNotExists("test_rmwsc_rider", ["pony_id"], ("test_rmwsc_littlehorse", "id"))
+
def test_rename_model_with_self_referential_m2m(self):
app_label = "test_rename_model_with_self_referential_m2m"