Loading django/db/migrations/autodetector.py +5 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,11 @@ class MigrationAutodetector(object): new_model_state = self.to_state.models[app_label, model_name] self.old_field_keys.update((app_label, model_name, x) for x, y in old_model_state.fields) self.new_field_keys.update((app_label, model_name, x) for x, y in new_model_state.fields) # Through model stuff # Through model map generation for app_label, model_name in sorted(self.old_model_keys): old_model_name = self.renamed_models.get((app_label, model_name), model_name) old_model_state = self.from_state.models[app_label, old_model_name] for field_name, field in old_model_state.fields: old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field_by_name(field_name)[0] if hasattr(old_field, "rel") and hasattr(old_field.rel, "through") and not old_field.rel.through._meta.auto_created: Loading tests/migrations/test_autodetector.py +15 −0 Original line number Diff line number Diff line Loading @@ -750,6 +750,21 @@ class AutodetectorTests(TestCase): self.assertEqual(action.__class__.__name__, "DeleteModel") self.assertEqual(action.name, "Attribution") def test_many_to_many_removed_before_through_model_2(self): """ Removing a model that contains a ManyToManyField and the "through" model in the same change must remove the field before the model to maintain consistency. """ before = self.make_project_state([self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution]) after = self.make_project_state([self.author_name]) # removes both the through model and ManyToMany autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() # Right number of migrations? self.assertNumberMigrations(changes, 'otherapp', 1) # Right number of actions? self.assertOperationTypes(changes, 'otherapp', 0, ["RemoveField", "RemoveField", "RemoveField", "DeleteModel", "DeleteModel"]) def test_m2m_w_through_multistep_remove(self): """ A model with a m2m field that specifies a "through" model cannot be removed in the same Loading Loading
django/db/migrations/autodetector.py +5 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,11 @@ class MigrationAutodetector(object): new_model_state = self.to_state.models[app_label, model_name] self.old_field_keys.update((app_label, model_name, x) for x, y in old_model_state.fields) self.new_field_keys.update((app_label, model_name, x) for x, y in new_model_state.fields) # Through model stuff # Through model map generation for app_label, model_name in sorted(self.old_model_keys): old_model_name = self.renamed_models.get((app_label, model_name), model_name) old_model_state = self.from_state.models[app_label, old_model_name] for field_name, field in old_model_state.fields: old_field = self.old_apps.get_model(app_label, old_model_name)._meta.get_field_by_name(field_name)[0] if hasattr(old_field, "rel") and hasattr(old_field.rel, "through") and not old_field.rel.through._meta.auto_created: Loading
tests/migrations/test_autodetector.py +15 −0 Original line number Diff line number Diff line Loading @@ -750,6 +750,21 @@ class AutodetectorTests(TestCase): self.assertEqual(action.__class__.__name__, "DeleteModel") self.assertEqual(action.name, "Attribution") def test_many_to_many_removed_before_through_model_2(self): """ Removing a model that contains a ManyToManyField and the "through" model in the same change must remove the field before the model to maintain consistency. """ before = self.make_project_state([self.book_with_multiple_authors_through_attribution, self.author_name, self.attribution]) after = self.make_project_state([self.author_name]) # removes both the through model and ManyToMany autodetector = MigrationAutodetector(before, after) changes = autodetector._detect_changes() # Right number of migrations? self.assertNumberMigrations(changes, 'otherapp', 1) # Right number of actions? self.assertOperationTypes(changes, 'otherapp', 0, ["RemoveField", "RemoveField", "RemoveField", "DeleteModel", "DeleteModel"]) def test_m2m_w_through_multistep_remove(self): """ A model with a m2m field that specifies a "through" model cannot be removed in the same Loading