summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Dufresne <jon.dufresne@gmail.com>2016-07-12 18:45:17 -0700
committerTim Graham <timograham@gmail.com>2016-07-12 21:45:17 -0400
commitb84ecaa736fd5e33bd5d95ac70e288db976a53ff (patch)
treec12ebf0632f495be5ec8dde9bb9224820a5bc50b
parent81963b37a92ef583b9f725f1a78dd2ca97c1ab95 (diff)
Fixed #26088 -- Made autodector detect changing proxy model to MTI.
-rw-r--r--django/db/migrations/autodetector.py14
-rw-r--r--tests/migrations/test_autodetector.py72
2 files changed, 86 insertions, 0 deletions
diff --git a/django/db/migrations/autodetector.py b/django/db/migrations/autodetector.py
index ae88a90465..c863dcaead 100644
--- a/django/db/migrations/autodetector.py
+++ b/django/db/migrations/autodetector.py
@@ -612,6 +612,20 @@ class MigrationAutodetector(object):
]
)
+ # Fix relationships if the model changed from a proxy model to a
+ # concrete model.
+ if (app_label, model_name) in self.old_proxy_keys:
+ for related_object in model_opts.related_objects:
+ self.add_operation(
+ related_object.related_model._meta.app_label,
+ operations.AlterField(
+ model_name=related_object.related_model._meta.object_name,
+ name=related_object.field.name,
+ field=related_object.field,
+ ),
+ dependencies=[(app_label, model_name, None, True)],
+ )
+
def generate_created_proxies(self):
"""
Makes CreateModel statements for proxy models.
diff --git a/tests/migrations/test_autodetector.py b/tests/migrations/test_autodetector.py
index 68c4e85b6d..7265330057 100644
--- a/tests/migrations/test_autodetector.py
+++ b/tests/migrations/test_autodetector.py
@@ -240,6 +240,7 @@ class AutodetectorTests(TestCase):
}, ("testapp.author", ))
author_proxy_notproxy = ModelState("testapp", "AuthorProxy", [], {}, ("testapp.author", ))
author_proxy_third = ModelState("thirdapp", "AuthorProxy", [], {"proxy": True}, ("testapp.author", ))
+ author_proxy_third_notproxy = ModelState("thirdapp", "AuthorProxy", [], {}, ("testapp.author", ))
author_proxy_proxy = ModelState("testapp", "AAuthorProxyProxy", [], {"proxy": True}, ("testapp.authorproxy", ))
author_unmanaged = ModelState("testapp", "AuthorUnmanaged", [], {"managed": False}, ("testapp.author", ))
author_unmanaged_managed = ModelState("testapp", "AuthorUnmanaged", [], {}, ("testapp.author", ))
@@ -336,6 +337,10 @@ class AutodetectorTests(TestCase):
("author", models.ForeignKey("thirdapp.AuthorProxy", models.CASCADE)),
("title", models.CharField(max_length=200)),
])
+ book_proxy_proxy_fk = ModelState("otherapp", "Book", [
+ ("id", models.AutoField(primary_key=True)),
+ ("author", models.ForeignKey("testapp.AAuthorProxyProxy", models.CASCADE)),
+ ])
book_migrations_fk = ModelState("otherapp", "Book", [
("id", models.AutoField(primary_key=True)),
("author", models.ForeignKey("migrations.UnmigratedModel", models.CASCADE)),
@@ -1291,6 +1296,73 @@ class AutodetectorTests(TestCase):
# The field name the FK on the book model points to
self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'pk_field')
+ def test_proxy_to_mti_with_fk_to_proxy(self):
+ # First, test the pk table and field name.
+ changes = self.get_changes(
+ [],
+ [self.author_empty, self.author_proxy_third, self.book_proxy_fk],
+ )
+ self.assertEqual(
+ changes['otherapp'][0].operations[0].fields[2][1].remote_field.model._meta.db_table,
+ 'testapp_author',
+ )
+ self.assertEqual(changes['otherapp'][0].operations[0].fields[2][1].remote_field.field_name, 'id')
+
+ # Change AuthorProxy to use MTI.
+ changes = self.get_changes(
+ [self.author_empty, self.author_proxy_third, self.book_proxy_fk],
+ [self.author_empty, self.author_proxy_third_notproxy, self.book_proxy_fk],
+ )
+ # Right number/type of migrations for the AuthorProxy model?
+ self.assertNumberMigrations(changes, 'thirdapp', 1)
+ self.assertOperationTypes(changes, 'thirdapp', 0, ['DeleteModel', 'CreateModel'])
+ # Right number/type of migrations for the Book model with a FK to
+ # AuthorProxy?
+ self.assertNumberMigrations(changes, 'otherapp', 1)
+ self.assertOperationTypes(changes, 'otherapp', 0, ['AlterField'])
+ # otherapp should depend on thirdapp.
+ self.assertMigrationDependencies(changes, 'otherapp', 0, [('thirdapp', 'auto_1')])
+ # Now, test the pk table and field name.
+ self.assertEqual(
+ changes['otherapp'][0].operations[0].field.remote_field.model._meta.db_table,
+ 'thirdapp_authorproxy',
+ )
+ self.assertEqual(changes['otherapp'][0].operations[0].field.remote_field.field_name, 'author_ptr')
+
+ def test_proxy_to_mti_with_fk_to_proxy_proxy(self):
+ # First, test the pk table and field name.
+ changes = self.get_changes(
+ [],
+ [self.author_empty, self.author_proxy, self.author_proxy_proxy, self.book_proxy_proxy_fk],
+ )
+ self.assertEqual(
+ changes['otherapp'][0].operations[0].fields[1][1].remote_field.model._meta.db_table,
+ 'testapp_author',
+ )
+ self.assertEqual(changes['otherapp'][0].operations[0].fields[1][1].remote_field.field_name, 'id')
+
+ # Change AuthorProxy to use MTI. FK still points to AAuthorProxyProxy,
+ # a proxy of AuthorProxy.
+ changes = self.get_changes(
+ [self.author_empty, self.author_proxy, self.author_proxy_proxy, self.book_proxy_proxy_fk],
+ [self.author_empty, self.author_proxy_notproxy, self.author_proxy_proxy, self.book_proxy_proxy_fk],
+ )
+ # Right number/type of migrations for the AuthorProxy model?
+ self.assertNumberMigrations(changes, 'testapp', 1)
+ self.assertOperationTypes(changes, 'testapp', 0, ['DeleteModel', 'CreateModel'])
+ # Right number/type of migrations for the Book model with a FK to
+ # AAuthorProxyProxy?
+ self.assertNumberMigrations(changes, 'otherapp', 1)
+ self.assertOperationTypes(changes, 'otherapp', 0, ['AlterField'])
+ # otherapp should depend on testapp.
+ self.assertMigrationDependencies(changes, 'otherapp', 0, [('testapp', 'auto_1')])
+ # Now, test the pk table and field name.
+ self.assertEqual(
+ changes['otherapp'][0].operations[0].field.remote_field.model._meta.db_table,
+ 'testapp_authorproxy',
+ )
+ self.assertEqual(changes['otherapp'][0].operations[0].field.remote_field.field_name, 'author_ptr')
+
def test_unmanaged_create(self):
"""Tests that the autodetector correctly deals with managed models."""
# First, we test adding an unmanaged model