From bf4dc5733fec86e7dfcdeddbcf4ce047c0b2f922 Mon Sep 17 00:00:00 2001 From: Markus Holtermann Date: Thu, 30 Apr 2015 01:39:50 +0200 Subject: [PATCH] [1.8.x] Fixed #24725 -- Allowed renaming of target models in ManyToMany relations This is a regression caused by introducing rendered migration states in 1aa3e09c2043 and the _meta refactoring in fb48eb05816b. Thanks to Danilo Bargen for reporting the issue and Marten Kenbeek and Tim Graham for triaging the bug and providing the initial test case. Backport of 63f9b633f9cb620a4c4764b47dca127706a8d7b4 from master --- django/db/migrations/operations/models.py | 2 +- docs/releases/1.8.1.txt | 3 +++ tests/migrations/test_operations.py | 26 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/django/db/migrations/operations/models.py b/django/db/migrations/operations/models.py index 2d75836da9..c0eb92a0ef 100644 --- a/django/db/migrations/operations/models.py +++ b/django/db/migrations/operations/models.py @@ -161,7 +161,7 @@ class RenameModel(Operation): # Get all of the related objects we need to repoint all_related_objects = ( f for f in model._meta.get_fields(include_hidden=True) - if f.auto_created and not f.concrete and not (f.hidden or f.many_to_many) + if f.auto_created and not f.concrete and (not f.hidden or f.many_to_many) ) # Rename the model state.models[app_label, self.new_name_lower] = state.models[app_label, self.old_name_lower] diff --git a/docs/releases/1.8.1.txt b/docs/releases/1.8.1.txt index d2b16d62da..b0bcbbfeea 100644 --- a/docs/releases/1.8.1.txt +++ b/docs/releases/1.8.1.txt @@ -72,6 +72,9 @@ Bugfixes * Restored the ability to use iterators as queryset filter arguments (:ticket:`24719`). +* Fixed a migration crash when renaming the target model of a many-to-many + relation (:ticket:`24725`). + Optimizations ============= diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index 7ff798f690..16d297afad 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -614,6 +614,32 @@ class OperationTests(OperationTestBase): self.assertEqual(Rider.objects.count(), 2) self.assertEqual(Pony._meta.get_field('riders').rel.through.objects.count(), 2) + def test_rename_m2m_target_model(self): + app_label = "test_rename_m2m_target_model" + project_state = self.apply_operations(app_label, ProjectState(), operations=[ + migrations.CreateModel("Rider", fields=[]), + migrations.CreateModel("Pony", fields=[ + ("riders", models.ManyToManyField("Rider")), + ]), + ]) + Pony = project_state.apps.get_model(app_label, "Pony") + Rider = project_state.apps.get_model(app_label, "Rider") + pony = Pony.objects.create() + rider = Rider.objects.create() + pony.riders.add(rider) + + project_state = self.apply_operations(app_label, project_state, operations=[ + migrations.RenameModel("Rider", "Rider2"), + ]) + Pony = project_state.apps.get_model(app_label, "Pony") + Rider = project_state.apps.get_model(app_label, "Rider2") + pony = Pony.objects.create() + rider = Rider.objects.create() + pony.riders.add(rider) + self.assertEqual(Pony.objects.count(), 2) + self.assertEqual(Rider.objects.count(), 2) + self.assertEqual(Pony._meta.get_field('riders').rel.through.objects.count(), 2) + def test_add_field(self): """ Tests the AddField operation.