浏览代码

Fix formfield_callback handling for Django 4.2a0

As of https://github.com/django/django/commit/e03cdf76e78ea992763df4d3e16217d298929301, formfield_callback can be set through ModelForm.meta. This new mechanism was overriding our metaclass hacking for WagtailAdminModelForm to accomplish the same thing, and as a result the custom Wagtail admin form fields were reverting to the Django defaults. We therefore need to update WagtailAdminModelForm to use the new mechanism when on Django >=4.2.
Matt Westcott 2 年之前
父节点
当前提交
0fd2d3d4c1
共有 3 个文件被更改,包括 27 次插入17 次删除
  1. 1 0
      CHANGELOG.txt
  2. 1 0
      docs/releases/4.1.md
  3. 25 17
      wagtail/admin/forms/models.py

+ 1 - 0
CHANGELOG.txt

@@ -28,6 +28,7 @@ Changelog
  * Fix: Revise colour usage so that privacy & locked indicators can be seen in Windows High Contrast mode (LB (Ben Johnston))
  * Fix: Ensure that disabled buttons have a consistent presentation on hover to indicate no interaction is available (Paarth Agarwal)
  * Fix: Update the 'Locked pages' report menu title so that it is consistent with other pages reports and its own title on viewing (Nicholas Johnson)
+ * Fix: Support `formfield_callback` handling on `ModelForm.Meta` for future Django 4.2 release (Matt Westcott)
 
 
 4.0.2 (xx.xx.xxxx) - IN DEVELOPMENT

+ 1 - 0
docs/releases/4.1.md

@@ -40,6 +40,7 @@ Wagtail 4.1 is designated a Long Term Support (LTS) release. Long Term Support r
  * Revise colour usage so that privacy & locked indicators can be seen in Windows High Contrast mode (LB (Ben Johnston))
  * Ensure that disabled buttons have a consistent presentation on hover to indicate no interaction is available (Paarth Agarwal)
  * Update the 'Locked pages' report menu title so that it is consistent with other pages reports and its own title on viewing (Nicholas Johnson)
+ * Support `formfield_callback` handling on `ModelForm.Meta` for future Django 4.2 release (Matt Westcott)
 
 ## Upgrade considerations
 

+ 25 - 17
wagtail/admin/forms/models.py

@@ -1,5 +1,6 @@
 import copy
 
+from django import VERSION as DJANGO_VERSION
 from django.core.exceptions import ImproperlyConfigured
 from django.db import models
 from modelcluster.forms import ClusterForm, ClusterFormMetaclass, ClusterFormOptions
@@ -100,25 +101,27 @@ class WagtailAdminModelFormOptions(PermissionedFormOptionsMixin, ClusterFormOpti
 class WagtailAdminModelFormMetaclass(PermissionedFormMetaclass, ClusterFormMetaclass):
     options_class = WagtailAdminModelFormOptions
 
-    # Override the behaviour of the regular ModelForm metaclass -
-    # which handles the translation of model fields to form fields -
-    # to use our own formfield_for_dbfield function to do that translation.
-    # This is done by sneaking a formfield_callback property into the class
-    # being defined (unless the class already provides a formfield_callback
-    # of its own).
-
-    # while we're at it, we'll also set extra_form_count to 0, as we're creating
-    # extra forms in JS
+    # set extra_form_count to 0, as we're creating extra forms in JS
     extra_form_count = 0
 
-    def __new__(cls, name, bases, attrs):
-        if "formfield_callback" not in attrs or attrs["formfield_callback"] is None:
-            attrs["formfield_callback"] = formfield_for_dbfield
-
-        new_class = super(WagtailAdminModelFormMetaclass, cls).__new__(
-            cls, name, bases, attrs
-        )
-        return new_class
+    if DJANGO_VERSION < (4, 2):
+
+        def __new__(cls, name, bases, attrs):
+            # Override the behaviour of the regular ModelForm metaclass -
+            # which handles the translation of model fields to form fields -
+            # to use our own formfield_for_dbfield function to do that translation.
+            # This is done by sneaking a formfield_callback property into the class
+            # being defined (unless the class already provides a formfield_callback
+            # of its own).
+            # As of Django 4.2, formfield_callback is available as an option in ModelForm.Meta
+            # so we don't have to hack the metaclass for this.
+            if "formfield_callback" not in attrs or attrs["formfield_callback"] is None:
+                attrs["formfield_callback"] = formfield_for_dbfield
+
+            new_class = super(WagtailAdminModelFormMetaclass, cls).__new__(
+                cls, name, bases, attrs
+            )
+            return new_class
 
     @classmethod
     def child_form(cls):
@@ -133,6 +136,11 @@ class WagtailAdminModelForm(
         self.for_user = kwargs.get("for_user")
         super().__init__(*args, **kwargs)
 
+    if DJANGO_VERSION >= (4, 2):
+
+        class Meta:
+            formfield_callback = formfield_for_dbfield
+
 
 # Now, any model forms built off WagtailAdminModelForm instead of ModelForm should pick up
 # the nice form fields defined in FORM_FIELD_OVERRIDES.