From 05e14e8eaf577e64dc45e26466ebb6117589e572 Mon Sep 17 00:00:00 2001 From: Andrew Godwin Date: Fri, 6 Sep 2013 12:32:52 -0500 Subject: [PATCH] Migration autodetector now corerctly deals with proxy models --- django/db/migrations/autodetector.py | 18 +++++++++++++++--- tests/migrations/test_autodetector.py | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py index 294f801435a..3343d216d46 100644 --- a/django/db/migrations/autodetector.py +++ b/django/db/migrations/autodetector.py @@ -50,8 +50,20 @@ class MigrationAutodetector(object): self.migrations = {} old_app_cache = self.from_state.render() new_app_cache = self.to_state.render() + # Prepare lists of old/new model keys that we care about + # (i.e. ignoring proxy ones) + old_model_keys = [ + (al, mn) + for al, mn in self.from_state.models.keys() + if not old_app_cache.get_model(al, mn)._meta.proxy + ] + new_model_keys = [ + (al, mn) + for al, mn in self.to_state.models.keys() + if not new_app_cache.get_model(al, mn)._meta.proxy + ] # Adding models. Phase 1 is adding models with no outward relationships. - added_models = set(self.to_state.models.keys()) - set(self.from_state.models.keys()) + added_models = set(new_model_keys) - set(old_model_keys) pending_add = {} for app_label, model_name in added_models: model_state = self.to_state.models[app_label, model_name] @@ -130,7 +142,7 @@ class MigrationAutodetector(object): ) self.add_dependency(app_label, other_app_label) # Removing models - removed_models = set(self.from_state.models.keys()) - set(self.to_state.models.keys()) + removed_models = set(old_model_keys) - set(new_model_keys) for app_label, model_name in removed_models: model_state = self.from_state.models[app_label, model_name] self.add_to_migration( @@ -140,7 +152,7 @@ class MigrationAutodetector(object): ) ) # Changes within models - kept_models = set(self.from_state.models.keys()).intersection(self.to_state.models.keys()) + kept_models = set(old_model_keys).intersection(new_model_keys) for app_label, model_name in kept_models: old_model_state = self.from_state.models[app_label, model_name] new_model_state = self.to_state.models[app_label, model_name] diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py index de3b156ba6c..a0ecd540cd2 100644 --- a/tests/migrations/test_autodetector.py +++ b/tests/migrations/test_autodetector.py @@ -16,6 +16,8 @@ class AutodetectorTests(TestCase): author_name_longer = ModelState("testapp", "Author", [("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=400))]) author_name_renamed = ModelState("testapp", "Author", [("id", models.AutoField(primary_key=True)), ("names", models.CharField(max_length=200))]) author_with_book = ModelState("testapp", "Author", [("id", models.AutoField(primary_key=True)), ("name", models.CharField(max_length=200)), ("book", models.ForeignKey("otherapp.Book"))]) + author_proxy = ModelState("testapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author", )) + author_proxy_notproxy = ModelState("testapp", "AuthorProxy", [], {}, ("testapp.author", )) other_pony = ModelState("otherapp", "Pony", [("id", models.AutoField(primary_key=True))]) other_stable = ModelState("otherapp", "Stable", [("id", models.AutoField(primary_key=True))]) third_thing = ModelState("thirdapp", "Thing", [("id", models.AutoField(primary_key=True))]) @@ -272,3 +274,28 @@ class AutodetectorTests(TestCase): self.assertEqual(action.__class__.__name__, "AlterUniqueTogether") self.assertEqual(action.name, "book") self.assertEqual(action.unique_together, set([("title", "author")])) + + def test_proxy_ignorance(self): + "Tests that the autodetector correctly ignores proxy models" + # First, we test adding a proxy model + before = self.make_project_state([self.author_empty]) + after = self.make_project_state([self.author_empty, self.author_proxy]) + autodetector = MigrationAutodetector(before, after) + changes = autodetector._detect_changes() + # Right number of migrations? + self.assertEqual(len(changes), 0) + + # Now, we test turning a proxy model into a non-proxy model + before = self.make_project_state([self.author_empty, self.author_proxy]) + after = self.make_project_state([self.author_empty, self.author_proxy_notproxy]) + autodetector = MigrationAutodetector(before, after) + changes = autodetector._detect_changes() + # Right number of migrations? + self.assertEqual(len(changes['testapp']), 1) + # Right number of actions? + migration = changes['testapp'][0] + self.assertEqual(len(migration.operations), 1) + # Right action? + action = migration.operations[0] + self.assertEqual(action.__class__.__name__, "CreateModel") + self.assertEqual(action.name, "AuthorProxy")