From 63f0e2df2a3af7b7225150a4ba6d63985b405855 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Fri, 16 Oct 2015 01:53:32 -0400 Subject: [PATCH] Refs #18012 -- Accounted for reverse proxy relations in migrations. Thanks to Markus for the suggestion and Tim for the review. --- django/db/migrations/state.py | 16 ++++++++++++---- tests/migrations/test_state.py | 10 ++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py index 2365e39ab6..5586d1b13a 100644 --- a/django/db/migrations/state.py +++ b/django/db/migrations/state.py @@ -41,13 +41,21 @@ def get_related_models_recursive(model): its superclass through the implicit *_ptr OneToOneField on the subclass. """ def _related_models(m): - return [ - f.related_model for f in m._meta.get_fields(include_parents=True, include_hidden=True) - if f.is_relation and f.related_model is not None and not isinstance(f.related_model, six.string_types) - ] + [ + related_models = [ subclass for subclass in m.__subclasses__() if issubclass(subclass, models.Model) ] + related_fields_models = set() + for f in m._meta.get_fields(include_parents=True, include_hidden=True): + if f.is_relation and f.related_model is not None and not isinstance(f.related_model, six.string_types): + related_fields_models.add(f.model) + related_models.append(f.related_model) + # Reverse accessors of foreign keys to proxy models + # are attached to their concrete proxied model. + opts = m._meta + if opts.proxy and m in related_fields_models: + related_models.append(opts.concrete_model) + return related_models seen = set() queue = _related_models(model) diff --git a/tests/migrations/test_state.py b/tests/migrations/test_state.py index 24185bdb78..ce12c5b96d 100644 --- a/tests/migrations/test_state.py +++ b/tests/migrations/test_state.py @@ -960,6 +960,16 @@ class RelatedModelsTests(SimpleTestCase): self.assertRelated(A, [B]) self.assertRelated(B, [A]) + def test_fk_through_proxy(self): + A = self.create_model("A") + B = self.create_model("B", bases=(A,), proxy=True) + C = self.create_model("C", bases=(B,), proxy=True) + D = self.create_model("D", foreign_keys=[models.ForeignKey('C', models.CASCADE)]) + self.assertRelated(A, [B, C, D]) + self.assertRelated(B, [A, C, D]) + self.assertRelated(C, [A, B, D]) + self.assertRelated(D, [A, B, C]) + def test_nested_fk(self): A = self.create_model("A", foreign_keys=[models.ForeignKey('B', models.CASCADE)]) B = self.create_model("B", foreign_keys=[models.ForeignKey('C', models.CASCADE)])