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)])