angrybeanie_wagtail/env/lib/python3.12/site-packages/wagtail/admin/viewsets/chooser.py
2025-07-25 21:32:16 +10:00

226 lines
9.2 KiB
Python

from django.db.models import ForeignKey
from django.urls import path
from django.utils.functional import cached_property
from django.utils.translation import gettext as _
from wagtail.admin.forms.models import register_form_field_override
from wagtail.admin.views.generic import chooser as chooser_views
from wagtail.admin.widgets.chooser import BaseChooser
from wagtail.blocks import ChooserBlock
from wagtail.telepath import register as register_telepath_adapter
from .base import ViewSet
class ChooserViewSet(ViewSet):
"""
A viewset that creates a chooser modal interface for choosing model instances.
"""
model = None
icon = "snippet" #: The icon to use in the header of the chooser modal, and on the chooser widget
choose_one_text = _(
"Choose"
) #: Label for the 'choose' button in the chooser widget when choosing an initial item
page_title = None #: Title text for the chooser modal (defaults to the same as ``choose_one_text``)`
choose_another_text = _(
"Choose another"
) #: Label for the 'choose' button in the chooser widget, when an item has already been chosen
edit_item_text = _("Edit") #: Label for the 'edit' button in the chooser widget
per_page = ViewSet.UNDEFINED #: Number of results to show per page
#: A list of URL query parameters that should be passed on unmodified as part of any links or
#: form submissions within the chooser modal workflow.
preserve_url_parameters = ["multiple"]
#: A list of URL query parameters that, if present in the url, should be applied as filters to the queryset.
#: (These should also be listed in `preserve_url_parameters`.)
url_filter_parameters = []
#: The view class to use for the overall chooser modal; must be a subclass of ``wagtail.admin.views.generic.chooser.ChooseView``.
choose_view_class = chooser_views.ChooseView
#: The view class used to render just the results panel within the chooser modal; must be a subclass of ``wagtail.admin.views.generic.chooser.ChooseResultsView``.
choose_results_view_class = chooser_views.ChooseResultsView
#: The view class used after an item has been chosen; must be a subclass of ``wagtail.admin.views.generic.chooser.ChosenView``.
chosen_view_class = chooser_views.ChosenView
#: The view class used after multiple items have been chosen; must be a subclass of ``wagtail.admin.views.generic.chooser.ChosenMultipleView``.
chosen_multiple_view_class = chooser_views.ChosenMultipleView
#: The view class used to handle submissions of the 'create' form; must be a subclass of ``wagtail.admin.views.generic.chooser.CreateView``.
create_view_class = chooser_views.CreateView
#: The base Widget class that the chooser widget will be derived from.
base_widget_class = BaseChooser
#: The adapter class used to map the widget class to its JavaScript implementation - see :ref:`streamfield_widget_api`.
#: Only required if the chooser uses custom JavaScript code.
widget_telepath_adapter_class = None
#: The base ChooserBlock class that the StreamField chooser block will be derived from.
base_block_class = ChooserBlock
#: Defaults to True; if False, the chooser widget will not automatically be registered for use in admin forms.
register_widget = True
#: Form class to use for the form in the "Create" tab of the modal.
creation_form_class = None
#: List of model fields that should be included in the creation form, if creation_form_class is not specified.
form_fields = None
#: List of model fields that should be excluded from the creation form, if creation_form_class.
#: If none of ``creation_form_class``, ``form_fields`` or ``exclude_form_fields`` are specified, the "Create" tab will be omitted.
exclude_form_fields = None
search_tab_label = _("Search") #: Label for the 'search' tab in the chooser modal
create_action_label = _(
"Create"
) #: Label for the submit button on the 'create' form
create_action_clicked_label = None #: Alternative text to display on the submit button after it has been clicked
creation_tab_label = None #: Label for the 'create' tab in the chooser modal (defaults to the same as create_action_label)
permission_policy = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.page_title is None:
self.page_title = self.choose_one_text
def get_common_view_kwargs(self, **kwargs):
return super().get_common_view_kwargs(
**{
"model": self.model,
"permission_policy": self.permission_policy,
"preserve_url_parameters": self.preserve_url_parameters,
"url_filter_parameters": self.url_filter_parameters,
"create_action_label": self.create_action_label,
"create_action_clicked_label": self.create_action_clicked_label,
"creation_form_class": self.creation_form_class,
"form_fields": self.form_fields,
"exclude_form_fields": self.exclude_form_fields,
"chosen_url_name": self.get_url_name("chosen"),
"chosen_multiple_url_name": self.get_url_name("chosen_multiple"),
"results_url_name": self.get_url_name("choose_results"),
"create_url_name": self.get_url_name("create"),
"per_page": self.per_page,
**kwargs,
}
)
@property
def choose_view(self):
view_class = self.inject_view_methods(
self.choose_view_class, ["get_object_list"]
)
return self.construct_view(
view_class,
icon=self.icon,
page_title=self.page_title,
search_tab_label=self.search_tab_label,
creation_tab_label=self.creation_tab_label,
)
@property
def choose_results_view(self):
view_class = self.inject_view_methods(
self.choose_results_view_class, ["get_object_list"]
)
return self.construct_view(view_class)
@property
def chosen_view(self):
return self.construct_view(self.chosen_view_class)
@property
def chosen_multiple_view(self):
return self.construct_view(self.chosen_multiple_view_class)
@property
def create_view(self):
return self.construct_view(self.create_view_class)
@cached_property
def model_name(self):
if isinstance(self.model, str):
return self.model.split(".")[-1]
else:
return self.model.__name__
@cached_property
def widget_class(self):
"""
Returns the form widget class for this chooser.
"""
if self.model is None:
widget_class_name = "ChooserWidget"
else:
if isinstance(self.model, str):
model_name = self.model.split(".")[-1]
else:
model_name = self.model.__name__
widget_class_name = "%sChooserWidget" % model_name
return type(
widget_class_name,
(self.base_widget_class,),
{
"model": self.model,
"choose_one_text": self.choose_one_text,
"choose_another_text": self.choose_another_text,
"link_to_chosen_text": self.edit_item_text,
"chooser_modal_url_name": self.get_url_name("choose"),
"icon": self.icon,
},
)
def get_block_class(self, name=None, module_path=None):
"""
Returns a StreamField ChooserBlock class using this chooser.
:param name: Name to give to the class; defaults to the model name with "ChooserBlock" appended
:param module_path: The dotted path of the module where the class can be imported from; used when
deconstructing the block definition for migration files.
"""
meta = type(
"Meta",
(self.base_block_class._meta_class,),
{
"icon": self.icon,
},
)
cls = type(
name or "%sChooserBlock" % self.model_name,
(self.base_block_class,),
{
"target_model": self.model,
"widget": self.widget_class(),
"Meta": meta,
},
)
if module_path:
cls.__module__ = module_path
return cls
def get_urlpatterns(self):
return super().get_urlpatterns() + [
path("", self.choose_view, name="choose"),
path("results/", self.choose_results_view, name="choose_results"),
path("chosen/<str:pk>/", self.chosen_view, name="chosen"),
path("chosen-multiple/", self.chosen_multiple_view, name="chosen_multiple"),
path("create/", self.create_view, name="create"),
]
def on_register(self):
if self.model and self.register_widget:
register_form_field_override(
ForeignKey, to=self.model, override={"widget": self.widget_class}
)
if self.widget_telepath_adapter_class:
adapter = self.widget_telepath_adapter_class()
register_telepath_adapter(adapter, self.widget_class)