Move SnippetViewSet.list_diplay definition to ModelViewSet

pull/10796/head
Sage Abdullah 2023-08-17 13:49:52 +01:00
rodzic 71aa1d2a3e
commit cd222898fd
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: EB1A33CC51CC0217
8 zmienionych plików z 83 dodań i 24 usunięć

Wyświetl plik

@ -48,7 +48,7 @@ There are a few attributes of `ModelAdmin` that need to be renamed/adjusted for
| ---------------------- | -------------------------- | ----- |
| `add_to_admin_menu` | {attr}`~SnippetViewSet.add_to_admin_menu` | Same attribute name, but the value defaults to `False` instead of `True`. Set to `True` to add a top-level menu item for the model. |
| `menu_icon` | {attr}`~SnippetViewSet.icon` | Same value, but different attribute name, as the icon is used throughout the admin and not just in the menu. |
| `list_display` | {attr}`~SnippetViewSet.list_display` | Same attribute name, but the list/tuple of strings must refer to existing attributes or methods on the model, not the `SnippetViewSet` class. If you have specified a string that refers to an attribute or method on the `ModelAdmin` class, you need to move it to the model. In addition, `list_display` now also supports instances of the `wagtail.admin.ui.tables.Column` component class. |
| `list_display` | {attr}`~wagtail.admin.viewsets.model.ModelViewSet.list_display` | Same attribute name, but the list/tuple of strings must refer to existing attributes or methods on the model, not the `SnippetViewSet` class. If you have specified a string that refers to an attribute or method on the `ModelAdmin` class, you need to move it to the model. In addition, `list_display` now also supports instances of the `wagtail.admin.ui.tables.Column` component class. |
| `list_filter` | {attr}`~SnippetViewSet.list_filter` | Same attribute name and value, but filtering is built on top of the django-filter package under the hood, which behaves differently to ModelAdmin's filters. See documentation for `SnippetViewSet.list_filter` and {attr}`~SnippetViewSet.filterset_class` for more details. |
| `form_fields_exclude` | {attr}`~wagtail.admin.viewsets.model.ModelViewSet.exclude_form_fields` | Same value, but different attribute name to better align with `ModelViewSet`. |
| - | {attr}`~SnippetViewSet.template_prefix` | New attribute. Set to the name of a template directory to override the `"wagtailsnippets/snippets/"` default. If set to `"modeladmin/"`, the template directory structure will be equal to what ModelAdmin uses. Make sure any custom templates are placed in the correct directory according to this prefix. See [](wagtailsnippets_templates) for more details. |

Wyświetl plik

@ -80,6 +80,7 @@ Viewsets are Wagtail's mechanism for defining a group of related admin views wit
:attr:`~django.db.models.Options.verbose_name_plural`.
.. autoattribute:: add_to_reference_index
.. autoattribute:: list_display
.. autoattribute:: index_view_class
.. autoattribute:: add_view_class
.. autoattribute:: edit_view_class
@ -145,7 +146,6 @@ Viewsets are Wagtail's mechanism for defining a group of related admin views wit
.. autoclass:: wagtail.snippets.views.snippets.SnippetViewSet
.. autoattribute:: model
.. autoattribute:: list_display
.. autoattribute:: list_export
.. autoattribute:: list_filter
.. autoattribute:: filterset_class

Wyświetl plik

@ -86,7 +86,7 @@ Similar URL customisations are also possible for the snippet chooser views throu
## Listing view
The {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.list_display` attribute can be set to specify the columns shown on the listing view. To customise the number of items to be displayed per page, you can set the {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.list_per_page` attribute (or {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.chooser_per_page` for the chooser listing).
The {attr}`~wagtail.admin.viewsets.model.ModelViewSet.list_display` attribute can be set to specify the columns shown on the listing view. To customise the number of items to be displayed per page, you can set the {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.list_per_page` attribute (or {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.chooser_per_page` for the chooser listing).
To customise the base queryset for the listing view, you could override the {meth}`~wagtail.snippets.views.snippets.SnippetViewSet.get_queryset` method. Additionally, the {attr}`~wagtail.snippets.views.snippets.SnippetViewSet.ordering` attribute can be used to specify the default ordering of the listing view.

Wyświetl plik

@ -115,3 +115,40 @@ class TestTemplateConfiguration(WagtailTestUtils, TestCase):
self.assertContains(
response, "<p>Some extra custom content</p>", html=True
)
class TestCustomColumns(WagtailTestUtils, TestCase):
def setUp(self):
self.user = self.login()
@classmethod
def setUpTestData(cls):
FeatureCompleteToy.objects.create(name="Racecar")
FeatureCompleteToy.objects.create(name="level")
FeatureCompleteToy.objects.create(name="Lotso")
def test_list_display(self):
index_url = reverse("feature_complete_toy:index")
response = self.client.get(index_url)
# "name" column
self.assertContains(response, "Racecar")
self.assertContains(response, "level")
self.assertContains(response, "Lotso")
# BooleanColumn("is_cool")
soup = self.get_soup(response.content)
help = soup.select_one("td:has(svg.icon-help)")
self.assertIsNotNone(help)
self.assertEqual(help.text.strip(), "None")
success = soup.select_one("td:has(svg.icon-success.w-text-positive-100)")
self.assertIsNotNone(success)
self.assertEqual(success.text.strip(), "True")
error = soup.select_one("td:has(svg.icon-error.w-text-critical-100)")
self.assertIsNotNone(error)
self.assertEqual(error.text.strip(), "False")
updated_at = soup.select("th a")[-1]
self.assertEqual(updated_at.text.strip(), "Updated")
self.assertEqual(updated_at["href"], f"{index_url}?ordering=_updated_at")

Wyświetl plik

@ -76,6 +76,7 @@ class ModelViewSet(ViewSet):
"add_url_name": self.get_url_name("add"),
"edit_url_name": self.get_url_name("edit"),
"header_icon": self.icon,
"list_display": self.list_display,
**kwargs,
}
@ -239,6 +240,32 @@ class ModelViewSet(ViewSet):
fallback=self.delete_view_class.template_name,
)
@cached_property
def list_display(self):
"""
A list or tuple, where each item is either:
- The name of a field on the model;
- The name of a callable or property on the model that accepts a single
parameter for the model instance; or
- An instance of the ``wagtail.admin.ui.tables.Column`` class.
If the name refers to a database field, the ability to sort the listing
by the database column will be offerred and the field's verbose name
will be used as the column header.
If the name refers to a callable or property, an ``admin_order_field``
attribute can be defined on it to point to the database column for
sorting. A ``short_description`` attribute can also be defined on the
callable or property to be used as the column header.
This list will be passed to the ``list_display`` attribute of the index
view. If left unset, the ``list_display`` attribute of the index view
will be used instead, which by default is defined as
``["__str__", wagtail.admin.ui.tables.UpdatedAtColumn()]``.
"""
return self.index_view_class.list_display
@cached_property
def menu_label(self):
return self.model_opts.verbose_name_plural.title()

Wyświetl plik

@ -624,21 +624,6 @@ class SnippetViewSet(ModelViewSet):
#: A subclass of ``wagtail.admin.filters.WagtailFilterSet``, which is a subclass of `django_filters.FilterSet <https://django-filter.readthedocs.io/en/stable/ref/filterset.html>`_. This will be passed to the ``filterset_class`` attribute of the index view.
filterset_class = None
#: A list or tuple, where each item is either:
#:
#: - The name of a field on the model;
#: - The name of a callable or property on the model that accepts a single parameter for the model instance; or
#: - An instance of the ``wagtail.admin.ui.tables.Column`` class.
#:
#: If the name refers to a database field, the ability to sort the listing by the database column will be offerred and the field's verbose name will be used as the column header.
#:
#: If the name refers to a callable or property, a ``admin_order_field`` attribute can be defined on it to point to the database column for sorting.
#: A ``short_description`` attribute can also be defined on the callable or property to be used as the column header.
#:
#: This list will be passed to the ``list_display`` attribute of the index view.
#: If left unset, the ``list_display`` attribute of the index view will be used instead, which by default is defined as ``["__str__", wagtail.admin.ui.tables.UpdatedAtColumn()]``.
list_display = None
#: A list or tuple, where each item is the name of model fields of type ``BooleanField``, ``CharField``, ``DateField``, ``DateTimeField``, ``IntegerField`` or ``ForeignKey``.
#: Alternatively, it can also be a dictionary that maps a field name to a list of lookup expressions.
#: This will be passed as django-filter's ``FilterSet.Meta.fields`` attribute. See `its documentation <https://django-filter.readthedocs.io/en/stable/guide/usage.html#generating-filters-with-meta-fields>`_ for more details.
@ -799,11 +784,6 @@ class SnippetViewSet(ModelViewSet):
self, "menu_item_is_registered", bool(self.menu_hook)
)
if not self.list_display:
self.list_display = self.index_view_class.list_display.copy()
if self.draftstate_enabled:
self.list_display += [LiveStatusTagColumn()]
# This edit handler has been bound to the model and is used for the views.
self._edit_handler = self.get_edit_handler()
@ -848,7 +828,6 @@ class SnippetViewSet(ModelViewSet):
index_url_name=self.get_url_name("list"),
index_results_url_name=self.get_url_name("list_results"),
delete_url_name=self.get_url_name("delete"),
list_display=self.list_display,
list_filter=self.list_filter,
list_export=self.list_export,
export_filename=self.get_export_filename(),
@ -1104,6 +1083,13 @@ class SnippetViewSet(ModelViewSet):
per_page=self.chooser_per_page,
)
@cached_property
def list_display(self):
list_display = super().list_display.copy()
if self.draftstate_enabled:
list_display.append(LiveStatusTagColumn())
return list_display
@cached_property
def icon(self):
return self.get_icon()

Wyświetl plik

@ -2140,3 +2140,10 @@ class GenericSnippetNoFieldIndexPage(GenericSnippetPage):
# Models to be registered with a ModelViewSet
class FeatureCompleteToy(models.Model):
name = models.CharField(max_length=255)
def is_cool(self):
if self.name == self.name[::-1]:
return True
if (lowered := self.name.lower()) == lowered[::-1]:
return None
return False

Wyświetl plik

@ -10,6 +10,7 @@ from django.utils.translation import gettext_lazy
from wagtail.admin import messages
from wagtail.admin.auth import user_passes_test
from wagtail.admin.ui.tables import BooleanColumn, UpdatedAtColumn
from wagtail.admin.views.generic import DeleteView, EditView, IndexView
from wagtail.admin.viewsets.base import ViewSet, ViewSetGroup
from wagtail.admin.viewsets.model import ModelViewSet, ModelViewSetGroup
@ -203,3 +204,4 @@ class FeatureCompleteToyViewSet(ModelViewSet):
add_to_admin_menu = True
template_prefix = "customprefix/"
index_template_name = "tests/fctoy_index.html"
list_display = ["name", BooleanColumn("is_cool"), UpdatedAtColumn()]