瀏覽代碼

Allow using plain strings in panel definitions in place of FieldPanel / InlinePanel (#12557)

Matt Westcott 4 月之前
父節點
當前提交
6047a66663
共有 5 個文件被更改,包括 60 次插入35 次删除
  1. 1 0
      CHANGELOG.txt
  2. 1 0
      docs/releases/6.4.md
  3. 4 1
      wagtail/admin/panels/group.py
  4. 31 0
      wagtail/admin/panels/model_utils.py
  5. 23 34
      wagtail/test/testapp/models.py

+ 1 - 0
CHANGELOG.txt

@@ -11,6 +11,7 @@ Changelog
  * Set sensible defaults for InlinePanel heading and label (Matt Westcott)
  * Limit tags autocompletion to 10 items and add delay to avoid performance issues with large number of matching tags (Aayushman Singh)
  * Add the ability to restrict what types of requests a Pages supports via `allowed_http_methods` (Andy Babic)
+ * Allow plain strings in panel definitions as shorthand for `FieldPanel` / `InlinePanel` (Matt Westcott)
  * Fix: Improve handling of translations for bulk page action confirmation messages (Matt Westcott)
  * Fix: Ensure custom rich text feature icons are correctly handled when provided as a list of SVG paths (Temidayo Azeez, Joel William, LB (Ben) Johnston)
  * Fix: Ensure manual edits to `StreamField` values do not throw an error (Stefan Hammer)

+ 1 - 0
docs/releases/6.4.md

@@ -21,6 +21,7 @@ depth: 1
  * Set sensible defaults for InlinePanel heading and label (Matt Westcott)
  * Limit tags autocompletion to 10 items and add delay to avoid performance issues with large number of matching tags (Aayushman Singh)
  * Add the ability to restrict what types of requests a Pages supports via [`allowed_http_methods`](#wagtail.models.Page.allowed_http_methods) (Andy Babic)
+ * Allow plain strings in panel definitions as shorthand for `FieldPanel` / `InlinePanel` (Matt Westcott)
 
 ### Bug fixes
 

+ 4 - 1
wagtail/admin/panels/group.py

@@ -71,7 +71,10 @@ class PanelGroup(Panel):
         return options
 
     def on_model_bound(self):
-        self.children = [child.bind_to_model(self.model) for child in self.children]
+        from .model_utils import expand_panel_list
+
+        child_panels = expand_panel_list(self.model, self.children)
+        self.children = [child.bind_to_model(self.model) for child in child_panels]
 
     @cached_property
     def child_identifiers(self):

+ 31 - 0
wagtail/admin/panels/model_utils.py

@@ -1,9 +1,12 @@
 import functools
 
+from django.core.exceptions import ImproperlyConfigured
+from django.db.models.fields.reverse_related import ManyToOneRel
 from django.forms.models import fields_for_model
 
 from wagtail.admin.forms.models import formfield_for_dbfield
 
+from .base import Panel
 from .field_panel import FieldPanel
 from .group import ObjectList
 
@@ -47,3 +50,31 @@ def get_edit_handler(model):
         panel = ObjectList(panels)
 
     return panel.bind_to_model(model)
+
+
+def expand_panel_list(model, panels):
+    """
+    Given a list which may be a mixture of Panel instances and strings (representing field/relation names),
+    expand it into a flat list of Panel instances
+    """
+    result = []
+    for panel in panels:
+        if isinstance(panel, Panel):
+            result.append(panel)
+
+        elif isinstance(panel, str):
+            field = model._meta.get_field(panel)
+            if isinstance(field, ManyToOneRel):
+                from .inline_panel import InlinePanel
+
+                result.append(InlinePanel(panel))
+            else:
+                result.append(FieldPanel(panel))
+
+        else:
+            raise ImproperlyConfigured(
+                "Invalid panel definition %r - expected Panel or string, got %r"
+                % (panel, type(panel))
+            )
+
+    return result

+ 23 - 34
wagtail/test/testapp/models.py

@@ -94,12 +94,7 @@ EVENT_AUDIENCE_CHOICES = (
 )
 
 
-COMMON_PANELS = (
-    FieldPanel("slug"),
-    FieldPanel("seo_title"),
-    FieldPanel("show_in_menus"),
-    FieldPanel("search_description"),
-)
+COMMON_PANELS = ("slug", "seo_title", "show_in_menus", "search_description")
 
 CUSTOM_PREVIEW_SIZES = [
     {
@@ -171,9 +166,9 @@ class CarouselItem(LinkFields):
     caption = models.CharField(max_length=255, blank=True)
 
     panels = [
-        FieldPanel("image"),
-        FieldPanel("embed_url"),
-        FieldPanel("caption"),
+        "image",
+        "embed_url",
+        "caption",
         MultiFieldPanel(LinkFields.panels, "Link"),
     ]
 
@@ -188,7 +183,7 @@ class RelatedLink(LinkFields):
     title = models.CharField(max_length=255, help_text="Link title")
 
     panels = [
-        FieldPanel("title"),
+        "title",
         MultiFieldPanel(LinkFields.panels, "Link"),
     ]
 
@@ -321,10 +316,7 @@ class EventPageSpeakerAward(TranslatableMixin, Orderable, models.Model):
     name = models.CharField("Award name", max_length=255)
     date_awarded = models.DateField(null=True, blank=True)
 
-    panels = [
-        FieldPanel("name"),
-        FieldPanel("date_awarded"),
-    ]
+    panels = ["name", "date_awarded"]
 
     class Meta(TranslatableMixin.Meta, Orderable.Meta):
         pass
@@ -352,9 +344,9 @@ class EventPageSpeaker(TranslatableMixin, Orderable, LinkFields, ClusterableMode
         return self.first_name + " " + self.last_name
 
     panels = [
-        FieldPanel("first_name"),
-        FieldPanel("last_name"),
-        FieldPanel("image"),
+        "first_name",
+        "last_name",
+        "image",
         MultiFieldPanel(LinkFields.panels, "Link"),
         InlinePanel("awards", label="Awards"),
     ]
@@ -423,16 +415,16 @@ class EventPage(Page):
 
     content_panels = [
         FieldPanel("title", classname="title"),
-        FieldPanel("date_from"),
-        FieldPanel("date_to"),
-        FieldPanel("time_from"),
-        FieldPanel("time_to"),
-        FieldPanel("location"),
+        "date_from",
+        "date_to",
+        "time_from",
+        "time_to",
+        "location",
         FieldPanel("audience", help_text="Who this event is for"),
-        FieldPanel("cost"),
-        FieldPanel("signup_link"),
+        "cost",
+        "signup_link",
         InlinePanel("carousel_items", label="Carousel items"),
-        FieldPanel("body"),
+        "body",
         InlinePanel(
             "speakers",
             label="Speaker",
@@ -440,7 +432,7 @@ class EventPage(Page):
             help_text="Put the keynote speaker first",
         ),
         InlinePanel("related_links", label="Related links"),
-        FieldPanel("categories"),
+        "categories",
         # InlinePanel related model uses `pk` not `id`
         InlinePanel("head_counts", label="Head Counts"),
     ]
@@ -2172,13 +2164,13 @@ class PersonPage(Page):
     content_panels = Page.content_panels + [
         MultiFieldPanel(
             [
-                FieldPanel("first_name"),
-                FieldPanel("last_name"),
+                "first_name",
+                "last_name",
             ],
             "Person",
         ),
-        InlinePanel("addresses", label="Address"),
-        InlinePanel("social_links", label="Social links"),
+        "addresses",
+        "social_links",
     ]
 
     class Meta:
@@ -2228,10 +2220,7 @@ class SocialLink(index.Indexed, ClusterableModel):
         to="tests.PersonPage", related_name="social_links", verbose_name="Person"
     )
 
-    panels = [
-        FieldPanel("url"),
-        FieldPanel("kind"),
-    ]
+    panels = ["url", "kind"]
 
     class Meta:
         verbose_name = "Social link"