From 0e8be73812a6e62d5a6b12a585d133b56bc2bf52 Mon Sep 17 00:00:00 2001 From: taulant Date: Mon, 30 Aug 2021 17:44:22 +0100 Subject: [PATCH] Fixed #32975 -- Fixed admin system check for inlines with foreign keys to proxy models. --- django/forms/models.py | 20 ++++++++++++++++---- tests/modeladmin/test_checks.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/django/forms/models.py b/django/forms/models.py index a88c384841..16681ba80b 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -1009,9 +1009,17 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False): fks_to_parent = [f for f in opts.fields if f.name == fk_name] if len(fks_to_parent) == 1: fk = fks_to_parent[0] - if not isinstance(fk, ForeignKey) or \ - (fk.remote_field.model != parent_model and - fk.remote_field.model not in parent_model._meta.get_parent_list()): + parent_list = parent_model._meta.get_parent_list() + if not isinstance(fk, ForeignKey) or ( + # ForeignKey to proxy models. + fk.remote_field.model._meta.proxy and + fk.remote_field.model._meta.proxy_for_model not in parent_list + ) or ( + # ForeignKey to concrete models. + not fk.remote_field.model._meta.proxy and + fk.remote_field.model != parent_model and + fk.remote_field.model not in parent_list + ): raise ValueError( "fk_name '%s' is not a ForeignKey to '%s'." % (fk_name, parent_model._meta.label) ) @@ -1021,11 +1029,15 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False): ) else: # Try to discover what the ForeignKey from model to parent_model is + parent_list = parent_model._meta.get_parent_list() fks_to_parent = [ f for f in opts.fields if isinstance(f, ForeignKey) and ( f.remote_field.model == parent_model or - f.remote_field.model in parent_model._meta.get_parent_list() + f.remote_field.model in parent_list or ( + f.remote_field.model._meta.proxy and + f.remote_field.model._meta.proxy_for_model in parent_list + ) ) ] if len(fks_to_parent) == 1: diff --git a/tests/modeladmin/test_checks.py b/tests/modeladmin/test_checks.py index f224770948..1d6f1ba023 100644 --- a/tests/modeladmin/test_checks.py +++ b/tests/modeladmin/test_checks.py @@ -4,7 +4,7 @@ from django.contrib.admin import BooleanFieldListFilter, SimpleListFilter from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline from django.contrib.admin.sites import AdminSite from django.core.checks import Error -from django.db.models import F, Field, Model +from django.db.models import CASCADE, F, Field, ForeignKey, Model from django.db.models.functions import Upper from django.forms.models import BaseModelFormSet from django.test import SimpleTestCase @@ -1121,6 +1121,33 @@ class FkNameCheckTests(CheckTestCase): self.assertIsValid(TestModelAdmin, ValidationTestModel) + def test_proxy_model_parent(self): + class Parent(Model): + pass + + class ProxyChild(Parent): + class Meta: + proxy = True + + class ProxyProxyChild(ProxyChild): + class Meta: + proxy = True + + class Related(Model): + proxy_child = ForeignKey(ProxyChild, on_delete=CASCADE) + + class InlineFkName(admin.TabularInline): + model = Related + fk_name = 'proxy_child' + + class InlineNoFkName(admin.TabularInline): + model = Related + + class ProxyProxyChildAdminFkName(admin.ModelAdmin): + inlines = [InlineFkName, InlineNoFkName] + + self.assertIsValid(ProxyProxyChildAdminFkName, ProxyProxyChild) + class ExtraCheckTests(CheckTestCase):