Parcourir la source

Fixed #32975 -- Fixed admin system check for inlines with foreign keys to proxy models.

taulant il y a 3 ans
Parent
commit
0e8be73812
2 fichiers modifiés avec 44 ajouts et 5 suppressions
  1. 16 4
      django/forms/models.py
  2. 28 1
      tests/modeladmin/test_checks.py

+ 16 - 4
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:

+ 28 - 1
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):