mirror of https://github.com/django/django.git
Fixed #23160 -- Correctly rename models with self referential fields.
Thanks to whitews AT gmail for the report.
This commit is contained in:
parent
2d542bf60c
commit
cbb29af1aa
|
@ -124,6 +124,10 @@ class RenameModel(Operation):
|
||||||
del state.models[app_label, self.old_name.lower()]
|
del state.models[app_label, self.old_name.lower()]
|
||||||
# Repoint the FKs and M2Ms pointing to us
|
# Repoint the FKs and M2Ms pointing to us
|
||||||
for related_object in (related_objects + related_m2m_objects):
|
for related_object in (related_objects + related_m2m_objects):
|
||||||
|
# Use the new related key for self referential related objects.
|
||||||
|
if related_object.model == model:
|
||||||
|
related_key = (app_label, self.new_name.lower())
|
||||||
|
else:
|
||||||
related_key = (
|
related_key = (
|
||||||
related_object.model._meta.app_label,
|
related_object.model._meta.app_label,
|
||||||
related_object.model._meta.object_name.lower(),
|
related_object.model._meta.object_name.lower(),
|
||||||
|
@ -152,12 +156,20 @@ class RenameModel(Operation):
|
||||||
related_objects = old_model._meta.get_all_related_objects()
|
related_objects = old_model._meta.get_all_related_objects()
|
||||||
related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
|
related_m2m_objects = old_model._meta.get_all_related_many_to_many_objects()
|
||||||
for related_object in (related_objects + related_m2m_objects):
|
for related_object in (related_objects + related_m2m_objects):
|
||||||
to_field = new_apps.get_model(
|
if related_object.model == old_model:
|
||||||
|
model = new_model
|
||||||
|
related_key = (app_label, self.new_name.lower())
|
||||||
|
else:
|
||||||
|
model = related_object.model
|
||||||
|
related_key = (
|
||||||
related_object.model._meta.app_label,
|
related_object.model._meta.app_label,
|
||||||
related_object.model._meta.object_name.lower(),
|
related_object.model._meta.object_name.lower(),
|
||||||
|
)
|
||||||
|
to_field = new_apps.get_model(
|
||||||
|
*related_key
|
||||||
)._meta.get_field_by_name(related_object.field.name)[0]
|
)._meta.get_field_by_name(related_object.field.name)[0]
|
||||||
schema_editor.alter_field(
|
schema_editor.alter_field(
|
||||||
related_object.model,
|
model,
|
||||||
related_object.field,
|
related_object.field,
|
||||||
to_field,
|
to_field,
|
||||||
)
|
)
|
||||||
|
|
|
@ -111,6 +111,7 @@ class OperationTestBase(MigrationTestBase):
|
||||||
[
|
[
|
||||||
("id", models.AutoField(primary_key=True)),
|
("id", models.AutoField(primary_key=True)),
|
||||||
("pony", models.ForeignKey("Pony")),
|
("pony", models.ForeignKey("Pony")),
|
||||||
|
("friend", models.ForeignKey("self"))
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
if mti_model:
|
if mti_model:
|
||||||
|
@ -406,6 +407,42 @@ class OperationTests(OperationTestBase):
|
||||||
self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id"))
|
self.assertFKExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_pony", "id"))
|
||||||
self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id"))
|
self.assertFKNotExists("test_rnmo_rider", ["pony_id"], ("test_rnmo_horse", "id"))
|
||||||
|
|
||||||
|
def test_rename_model_with_self_referential_fk(self):
|
||||||
|
"""
|
||||||
|
Tests the RenameModel operation on model with self referential FK.
|
||||||
|
"""
|
||||||
|
project_state = self.set_up_test_model("test_rmwsrf", related_model=True)
|
||||||
|
# Test the state alteration
|
||||||
|
operation = migrations.RenameModel("Rider", "HorseRider")
|
||||||
|
self.assertEqual(operation.describe(), "Rename model Rider to HorseRider")
|
||||||
|
new_state = project_state.clone()
|
||||||
|
operation.state_forwards("test_rmwsrf", new_state)
|
||||||
|
self.assertNotIn(("test_rmwsrf", "rider"), new_state.models)
|
||||||
|
self.assertIn(("test_rmwsrf", "horserider"), new_state.models)
|
||||||
|
# Remember, RenameModel also repoints all incoming FKs and M2Ms
|
||||||
|
self.assertEqual("test_rmwsrf.HorseRider", new_state.models["test_rmwsrf", "horserider"].fields[2][1].rel.to)
|
||||||
|
# Test the database alteration
|
||||||
|
self.assertTableExists("test_rmwsrf_rider")
|
||||||
|
self.assertTableNotExists("test_rmwsrf_horserider")
|
||||||
|
if connection.features.supports_foreign_keys:
|
||||||
|
self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id"))
|
||||||
|
self.assertFKNotExists("test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
operation.database_forwards("test_rmwsrf", editor, project_state, new_state)
|
||||||
|
self.assertTableNotExists("test_rmwsrf_rider")
|
||||||
|
self.assertTableExists("test_rmwsrf_horserider")
|
||||||
|
if connection.features.supports_foreign_keys:
|
||||||
|
self.assertFKNotExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id"))
|
||||||
|
self.assertFKExists("test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
|
||||||
|
# And test reversal
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
operation.database_backwards("test_rmwsrf", editor, new_state, project_state)
|
||||||
|
self.assertTableExists("test_rmwsrf_rider")
|
||||||
|
self.assertTableNotExists("test_rmwsrf_horserider")
|
||||||
|
if connection.features.supports_foreign_keys:
|
||||||
|
self.assertFKExists("test_rmwsrf_rider", ["friend_id"], ("test_rmwsrf_rider", "id"))
|
||||||
|
self.assertFKNotExists("test_rmwsrf_horserider", ["friend_id"], ("test_rmwsrf_horserider", "id"))
|
||||||
|
|
||||||
def test_add_field(self):
|
def test_add_field(self):
|
||||||
"""
|
"""
|
||||||
Tests the AddField operation.
|
Tests the AddField operation.
|
||||||
|
|
Loading…
Reference in New Issue