From 63f9b633f9cb620a4c4764b47dca127706a8d7b4 Mon Sep 17 00:00:00 2001 From: Markus Holtermann Date: Thu, 30 Apr 2015 01:39:50 +0200 Subject: [PATCH] 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. --- 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 56cb8fe608..69998331fb 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 b8354f32d9..de5cf5813c 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').remote_field.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').remote_field.through.objects.count(), 2) + def test_add_field(self): """ Tests the AddField operation.