Move SnippetViewSet.get_edit_handler() to ModelViewSet

However, keep the logic for falling back to extracting panel definitions
from the model class as snippets-specific. ModelViewSets are likely used
with models that are more low-level and thus we want developers to
explicitly define the fields that are editable in the admin, just like
how Django's ModelForm works.
pull/10830/head
Sage Abdullah 2023-08-24 15:06:48 +01:00
rodzic 0af4dd5fd9
commit b4881cad64
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: EB1A33CC51CC0217
4 zmienionych plików z 64 dodań i 32 usunięć

Wyświetl plik

@ -77,6 +77,7 @@ Viewsets are Wagtail's mechanism for defining a group of related admin views wit
Used in place of :attr:`form_fields` to indicate that all of the model's fields except the ones listed here should appear in the create / edit forms. Either ``form_fields`` or ``exclude_form_fields`` must be supplied (unless :meth:`get_form_class` is being overridden). Used in place of :attr:`form_fields` to indicate that all of the model's fields except the ones listed here should appear in the create / edit forms. Either ``form_fields`` or ``exclude_form_fields`` must be supplied (unless :meth:`get_form_class` is being overridden).
.. automethod:: get_form_class .. automethod:: get_form_class
.. automethod:: get_edit_handler
.. autoattribute:: menu_label .. autoattribute:: menu_label
@ -195,7 +196,6 @@ Viewsets are Wagtail's mechanism for defining a group of related admin views wit
.. autoattribute:: chooser_viewset_class .. autoattribute:: chooser_viewset_class
.. automethod:: get_queryset .. automethod:: get_queryset
.. automethod:: get_edit_handler .. automethod:: get_edit_handler
.. automethod:: get_form_class
.. automethod:: get_index_template .. automethod:: get_index_template
.. automethod:: get_index_results_template .. automethod:: get_index_results_template
.. automethod:: get_create_template .. automethod:: get_create_template

Wyświetl plik

@ -10,6 +10,7 @@ from wagtail.admin.admin_url_finder import (
ModelAdminURLFinder, ModelAdminURLFinder,
register_admin_url_finder, register_admin_url_finder,
) )
from wagtail.admin.panels.group import ObjectList
from wagtail.admin.views import generic from wagtail.admin.views import generic
from wagtail.admin.views.generic import history, usage from wagtail.admin.views.generic import history, usage
from wagtail.models import ReferenceIndex from wagtail.models import ReferenceIndex
@ -151,6 +152,7 @@ class ModelViewSet(ViewSet):
def get_add_view_kwargs(self, **kwargs): def get_add_view_kwargs(self, **kwargs):
return { return {
"panel": self._edit_handler,
"form_class": self.get_form_class(), "form_class": self.get_form_class(),
"template_name": self.create_template_name, "template_name": self.create_template_name,
**kwargs, **kwargs,
@ -158,6 +160,7 @@ class ModelViewSet(ViewSet):
def get_edit_view_kwargs(self, **kwargs): def get_edit_view_kwargs(self, **kwargs):
return { return {
"panel": self._edit_handler,
"form_class": self.get_form_class(for_update=True), "form_class": self.get_form_class(for_update=True),
"template_name": self.edit_template_name, "template_name": self.edit_template_name,
**kwargs, **kwargs,
@ -507,6 +510,11 @@ class ModelViewSet(ViewSet):
""" """
Returns the form class to use for the create / edit forms. Returns the form class to use for the create / edit forms.
""" """
# If an edit handler is defined, use it to construct the form class.
if self._edit_handler:
return self._edit_handler.get_form_class()
# Otherwise, use Django's modelform_factory.
fields = self.get_form_fields() fields = self.get_form_fields()
exclude = self.get_exclude_form_fields() exclude = self.get_exclude_form_fields()
@ -535,6 +543,37 @@ class ModelViewSet(ViewSet):
""" """
return getattr(self, "exclude_form_fields", None) return getattr(self, "exclude_form_fields", None)
def get_edit_handler(self):
"""
Returns the appropriate edit handler for this ``ModelViewSet`` class.
It can be defined either on the model itself or on the ``ModelViewSet``,
as the ``edit_handler`` or ``panels`` properties. If none of these are
defined, it will return ``None`` and the form will be constructed as
a Django form using :meth:`get_form_class` (without using
:ref:`forms_panels_overview`).
"""
if hasattr(self, "edit_handler"):
edit_handler = self.edit_handler
elif hasattr(self, "panels"):
panels = self.panels
edit_handler = ObjectList(panels)
elif hasattr(self.model, "edit_handler"):
edit_handler = self.model.edit_handler
elif hasattr(self.model, "panels"):
panels = self.model.panels
edit_handler = ObjectList(panels)
else:
return None
return edit_handler.bind_to_model(self.model)
@cached_property
def _edit_handler(self):
"""
An edit handler that has been bound to the model class,
to be used across views.
"""
return self.get_edit_handler()
@property @property
def url_finder_class(self): def url_finder_class(self):
return type( return type(

Wyświetl plik

@ -13,8 +13,7 @@ from django.utils.translation import gettext_lazy
from wagtail import hooks from wagtail import hooks
from wagtail.admin.checks import check_panels_in_model from wagtail.admin.checks import check_panels_in_model
from wagtail.admin.panels.group import ObjectList from wagtail.admin.panels import ObjectList, extract_panel_definitions_from_model_class
from wagtail.admin.panels.model_utils import extract_panel_definitions_from_model_class
from wagtail.admin.ui.components import MediaContainer from wagtail.admin.ui.components import MediaContainer
from wagtail.admin.ui.side_panels import PreviewSidePanel from wagtail.admin.ui.side_panels import PreviewSidePanel
from wagtail.admin.ui.tables import ( from wagtail.admin.ui.tables import (
@ -548,6 +547,12 @@ class WorkflowHistoryDetailView(
class SnippetViewSet(ModelViewSet): class SnippetViewSet(ModelViewSet):
""" """
A viewset that instantiates the admin views for snippets. A viewset that instantiates the admin views for snippets.
All attributes and methods from
:class:`~wagtail.admin.viewsets.model.ModelViewSet` are available.
For more information on how to use this class,
see :ref:`wagtailsnippets_custom_admin_views`.
""" """
#: The model class to be registered as a snippet with this viewset. #: The model class to be registered as a snippet with this viewset.
@ -667,9 +672,6 @@ class SnippetViewSet(ModelViewSet):
self, "menu_item_is_registered", bool(self.menu_hook) self, "menu_item_is_registered", bool(self.menu_hook)
) )
# This edit handler has been bound to the model and is used for the views.
self._edit_handler = self.get_edit_handler()
@cached_property @cached_property
def url_prefix(self): def url_prefix(self):
# SnippetViewSet historically allows overriding the URL prefix via the # SnippetViewSet historically allows overriding the URL prefix via the
@ -731,14 +733,12 @@ class SnippetViewSet(ModelViewSet):
def get_add_view_kwargs(self, **kwargs): def get_add_view_kwargs(self, **kwargs):
return super().get_add_view_kwargs( return super().get_add_view_kwargs(
panel=self._edit_handler,
preview_url_name=self.get_url_name("preview_on_add"), preview_url_name=self.get_url_name("preview_on_add"),
**kwargs, **kwargs,
) )
def get_edit_view_kwargs(self, **kwargs): def get_edit_view_kwargs(self, **kwargs):
return super().get_edit_view_kwargs( return super().get_edit_view_kwargs(
panel=self._edit_handler,
preview_url_name=self.get_url_name("preview_on_edit"), preview_url_name=self.get_url_name("preview_on_edit"),
workflow_history_url_name=self.get_url_name("workflow_history"), workflow_history_url_name=self.get_url_name("workflow_history"),
confirm_workflow_cancellation_url_name=self.get_url_name( confirm_workflow_cancellation_url_name=self.get_url_name(
@ -1257,32 +1257,20 @@ class SnippetViewSet(ModelViewSet):
def get_edit_handler(self): def get_edit_handler(self):
""" """
Returns the appropriate edit handler for this ``SnippetViewSet`` class. Like :meth:`ModelViewSet.get_edit_handler()
It can be defined either on the model itself or on the ``SnippetViewSet``, <wagtail.admin.viewsets.model.ModelViewSet.get_edit_handler>`,
as the ``edit_handler`` or ``panels`` properties. Falls back to but falls back to extracting panel definitions from the model class
extracting panel / edit handler definitions from the model class. if no edit handler is defined.
""" """
if hasattr(self, "edit_handler"): edit_handler = super().get_edit_handler()
edit_handler = self.edit_handler if edit_handler:
elif hasattr(self, "panels"): return edit_handler
panels = self.panels
edit_handler = ObjectList(panels)
elif hasattr(self.model, "edit_handler"):
edit_handler = self.model.edit_handler
elif hasattr(self.model, "panels"):
panels = self.model.panels
edit_handler = ObjectList(panels)
else:
exclude = self.get_exclude_form_fields() exclude = self.get_exclude_form_fields()
panels = extract_panel_definitions_from_model_class( panels = extract_panel_definitions_from_model_class(self.model, exclude=exclude)
self.model, exclude=exclude
)
edit_handler = ObjectList(panels) edit_handler = ObjectList(panels)
return edit_handler.bind_to_model(self.model) return edit_handler.bind_to_model(self.model)
def get_form_class(self, for_update=False):
return self._edit_handler.get_form_class()
def register_chooser_viewset(self): def register_chooser_viewset(self):
viewsets.register(self.chooser_viewset) viewsets.register(self.chooser_viewset)

Wyświetl plik

@ -11,6 +11,7 @@ from django.utils.translation import gettext_lazy
from wagtail.admin import messages from wagtail.admin import messages
from wagtail.admin.auth import user_passes_test from wagtail.admin.auth import user_passes_test
from wagtail.admin.filters import WagtailFilterSet from wagtail.admin.filters import WagtailFilterSet
from wagtail.admin.panels import FieldPanel
from wagtail.admin.ui.tables import BooleanColumn, UpdatedAtColumn from wagtail.admin.ui.tables import BooleanColumn, UpdatedAtColumn
from wagtail.admin.views.generic import DeleteView, EditView, IndexView from wagtail.admin.views.generic import DeleteView, EditView, IndexView
from wagtail.admin.viewsets.base import ViewSet, ViewSetGroup from wagtail.admin.viewsets.base import ViewSet, ViewSetGroup
@ -206,7 +207,6 @@ class FeatureCompleteToyViewSet(ModelViewSet):
url_prefix = "feature-complete-toy" url_prefix = "feature-complete-toy"
menu_label = "Feature Complete Toys" menu_label = "Feature Complete Toys"
icon = "media" icon = "media"
exclude_form_fields = ()
template_prefix = "customprefix/" template_prefix = "customprefix/"
index_template_name = "tests/fctoy_index.html" index_template_name = "tests/fctoy_index.html"
list_display = ["name", BooleanColumn("is_cool"), UpdatedAtColumn()] list_display = ["name", BooleanColumn("is_cool"), UpdatedAtColumn()]
@ -220,6 +220,11 @@ class FeatureCompleteToyViewSet(ModelViewSet):
inspect_view_enabled = True inspect_view_enabled = True
inspect_view_fields = ["strid", "release_date"] inspect_view_fields = ["strid", "release_date"]
panels = [
FieldPanel("name"),
FieldPanel("release_date"),
]
class FCToyAlt1ViewSet(ModelViewSet): class FCToyAlt1ViewSet(ModelViewSet):
model = FeatureCompleteToy model = FeatureCompleteToy