Browse Source

Render form using top-level panel if available in generic CreateView/EditView templates

Sage Abdullah 1 year ago
parent
commit
336ec6ea10

+ 8 - 0
docs/extending/generic_views.md

@@ -86,6 +86,14 @@ If you would like to make further customisations to the filtering mechanism, you
 
 You can add the ability to export the listing view to a spreadsheet by setting the {attr}`~ModelViewSet.list_export` attribute to specify the columns to be exported. The {attr}`~ModelViewSet.export_filename` attribute can be used to customise the file name of the exported spreadsheet.
 
+(modelviewset_create_edit)=
+
+### Create and edit views
+
+You can define a `panels` or `edit_handler` attribute on the `ModelViewSet` or your Django model to use Wagtail's panels mechanism. For more details, see [](forms_panels_overview).
+
+If neither `panels` nor `edit_handler` is defined and the {meth}`~ModelViewSet.get_edit_handler` method is not overridden, the form will be rendered as a plain Django form. You can customise the form by setting the {attr}`~ModelViewSet.form_fields` attribute to specify the fields to be shown on the form. Alternatively, you can set the {attr}`~ModelViewSet.exclude_form_fields` attribute to specify the fields to be excluded from the form. If panels are not used, you must define `form_fields` or `exclude_form_fields`, unless {meth}`~ModelViewSet.get_form_class` is overridden.
+
 (modelviewset_inspect)=
 
 ### Inspect view

+ 16 - 12
wagtail/admin/templates/wagtailadmin/generic/form.html

@@ -12,19 +12,23 @@
             {% endfor %}
         {% endblock %}
 
-        {% block hidden_fields %}
-            {% for field in form.hidden_fields %}{{ field }}{% endfor %}
-        {% endblock %}
-
-        <ul class="fields">
-            {% block visible_fields %}
-                {% for field in form.visible_fields %}
-                    <li>
-                        {% include "wagtailadmin/shared/field.html" %}
-                    </li>
-                {% endfor %}
+        {% if panel %}
+            {{ panel.render_form_content }}
+        {% else %}
+            {% block hidden_fields %}
+                {% for field in form.hidden_fields %}{{ field }}{% endfor %}
             {% endblock %}
-        </ul>
+
+            <ul class="fields">
+                {% block visible_fields %}
+                    {% for field in form.visible_fields %}
+                        <li>
+                            {% include "wagtailadmin/shared/field.html" %}
+                        </li>
+                    {% endfor %}
+                {% endblock %}
+            </ul>
+        {% endif %}
 
         {% block actions %}
             <button type="submit" class="button">{{ submit_button_label }}</button>

+ 30 - 0
wagtail/admin/tests/viewsets/test_model_viewset.py

@@ -1250,3 +1250,33 @@ class TestListingButtons(WagtailTestUtils, TestCase):
             self.assertEqual(rendered_button.text.strip(), label)
             self.assertEqual(rendered_button.attrs.get("aria-label"), aria_label)
             self.assertEqual(rendered_button.attrs.get("href"), url)
+
+
+class TestEditHandler(WagtailTestUtils, TestCase):
+    def setUp(self):
+        self.user = self.login()
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.object = FeatureCompleteToy.objects.create(name="Test Toy")
+        cls.url = reverse("feature_complete_toy:edit", args=(quote(cls.object.pk),))
+
+    def test_edit_form_rendered_with_panels(self):
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, 200)
+        self.assertTemplateUsed(response, "wagtailadmin/shared/panel.html")
+
+        soup = self.get_soup(response.content)
+
+        # Minimap should be rendered
+        minimap_container = soup.select_one("[data-minimap-container]")
+        self.assertIsNotNone(minimap_container)
+
+        # Form should be rendered using panels
+        panels = soup.select("[data-panel]")
+        self.assertEqual(len(panels), 2)
+        headings = ["Name", "Release date"]
+        for expected_heading, panel in zip(headings, panels):
+            rendered_heading = panel.select_one("[data-panel-heading-text]")
+            self.assertIsNotNone(rendered_heading)
+            self.assertEqual(rendered_heading.text.strip(), expected_heading)