From f9c7df49c8af97bad3ac101ea7231277422e2436 Mon Sep 17 00:00:00 2001 From: Shlomo Markowitz <75799735+smark-1@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:56:01 -0500 Subject: [PATCH] Add support for modifying default page listing ordering --- CHANGELOG.txt | 1 + CONTRIBUTORS.md | 1 + docs/reference/pages/model_reference.md | 30 ++++++++++++ docs/releases/6.0.md | 1 + .../admin/tests/pages/test_explorer_view.py | 48 +++++++++++++++++++ wagtail/admin/views/pages/listing.py | 12 +++++ wagtail/models/__init__.py | 10 ++++ 7 files changed, 103 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 8719ca72fdde..6c71782830a7 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -18,6 +18,7 @@ Changelog * Use a single instance of `PagePermissionPolicy` in `wagtail.permissions` module (Sage Abdullah) * Add max tag length validation for multiple uploads (documents/images) (Temidayo Azeez) * Ensure expanded side panel does not overlap form content for most viewports (Chiemezuo Akujobi) + * Add ability to modify the default ordering for the page explorer view (Shlomo Markowitz) * Fix: Update system check for overwriting storage backends to recognise the `STORAGES` setting introduced in Django 4.2 (phijma-leukeleu) * Fix: Prevent password change form from raising a validation error when browser autocomplete fills in the "Old password" field (Chiemezuo Akujobi) * Fix: Ensure that the legacy dropdown options, when closed, do not get accidentally clicked by other interactions wide viewports (CheesyPhoenix, Christer Jensen) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2c6932aa99c1..a9ab719dc36a 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -773,6 +773,7 @@ * Mariana Bedran Lesche * Bhuvnesh Sharma * Ben Morse +* Shlomo Markowitz ## Translators diff --git a/docs/reference/pages/model_reference.md b/docs/reference/pages/model_reference.md index c4557676a2d2..3619bd9b50ae 100644 --- a/docs/reference/pages/model_reference.md +++ b/docs/reference/pages/model_reference.md @@ -218,6 +218,36 @@ See also [django-treebeard](https://django-treebeard.readthedocs.io/en/latest/in .. automethod:: copy_for_translation + .. method:: get_admin_default_ordering + + Returns the default sort order for child pages to be sorted in viewing the admin pages index and not seeing search results. + + The following sort orders are available: + + - ``'content_type'`` + - ``'-content_type'`` + - ``'latest_revision_created_at'`` + - ``'-latest_revision_created_at'`` + - ``'live'`` + - ``'-live'`` + - ``'ord'`` + - ``'title'`` + - ``'-title'`` + + For example to make a page sort by title for all the child pages only if there are < 20 pages. + + .. code-block:: python + + class BreadsIndexPage(Page): + def get_admin_default_ordering(self): + if Page.objects.child_of(self).count() < 20: + return 'title' + return self.admin_default_ordering + + .. attribute:: admin_default_ordering + + An attribute version for the method ``get_admin_default_ordering()``, defaults to ``'-latest_revision_created_at'``. + .. autoattribute:: localized .. autoattribute:: localized_draft diff --git a/docs/releases/6.0.md b/docs/releases/6.0.md index 3447c3890e76..99df229b29bf 100644 --- a/docs/releases/6.0.md +++ b/docs/releases/6.0.md @@ -28,6 +28,7 @@ depth: 1 * Use a single instance of `PagePermissionPolicy` in `wagtail.permissions` module (Sage Abdullah) * Add max tag length validation for multiple uploads (documents/images) (Temidayo Azeez) * Ensure expanded side panel does not overlap form content for most viewports (Chiemezuo Akujobi) + * Add ability to [modify the default ordering](page_model_ref) for the page explorer view (Shlomo Markowitz) ### Bug fixes diff --git a/wagtail/admin/tests/pages/test_explorer_view.py b/wagtail/admin/tests/pages/test_explorer_view.py index f4bc249c5578..be1c6ba129fb 100644 --- a/wagtail/admin/tests/pages/test_explorer_view.py +++ b/wagtail/admin/tests/pages/test_explorer_view.py @@ -126,6 +126,54 @@ def test_ordering(self): page_ids, [self.child_page.id, self.new_page.id, self.old_page.id] ) + def test_change_default_child_page_ordering_attribute(self): + # save old get_default_order to reset at end of test + # overriding class methods does not reset at end of test case + default_order = self.root_page.__class__.admin_default_ordering + self.root_page.__class__.admin_default_ordering = "title" + response = self.client.get( + reverse("wagtailadmin_explore", args=(self.root_page.id,)) + ) + + # child pages should be ordered by title + page_ids = [page.id for page in response.context["pages"]] + self.assertEqual( + page_ids, [self.child_page.id, self.new_page.id, self.old_page.id] + ) + self.assertEqual("title", self.root_page.get_admin_default_ordering()) + self.assertEqual(response.context["ordering"], "title") + + # reset default order at the end of the test + self.root_page.__class__.admin_default_ordering = default_order + + def test_change_default_child_page_ordering_method(self): + # save old get_default_order to reset at end of test + # overriding class methods does not reset at end of test case + default_order_function = self.root_page.__class__.get_admin_default_ordering + + def get_default_order(obj): + return "-title" + + # override get_default_order_method + self.root_page.__class__.get_admin_default_ordering = get_default_order + + response = self.client.get( + reverse("wagtailadmin_explore", args=(self.root_page.id,)) + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "wagtailadmin/pages/index.html") + + # child pages should be ordered by title + page_ids = [page.id for page in response.context["pages"]] + self.assertEqual("-title", self.root_page.get_admin_default_ordering()) + self.assertEqual( + page_ids, [self.old_page.id, self.new_page.id, self.child_page.id] + ) + self.assertEqual(response.context["ordering"], "-title") + + # reset default order function at the end of the test + self.root_page.__class__.get_admin_default_ordering = default_order_function + def test_reverse_ordering(self): response = self.client.get( reverse("wagtailadmin_explore", args=(self.root_page.id,)), diff --git a/wagtail/admin/views/pages/listing.py b/wagtail/admin/views/pages/listing.py index 4a73e1f0eb26..f24d6ac391d4 100644 --- a/wagtail/admin/views/pages/listing.py +++ b/wagtail/admin/views/pages/listing.py @@ -321,6 +321,18 @@ def get_context_data(self, **kwargs): ) return context + def get_ordering(self): + """ + Use the parent Page's `get_admin_default_ordering` method. + """ + if self.query_string: + # default to ordering by relevance + return None + elif not self.request.GET.get("ordering"): + return self.parent_page.get_admin_default_ordering() + + return super().get_ordering() + class IndexResultsView(BaseIndexView): template_name = "wagtailadmin/pages/index_results.html" diff --git a/wagtail/models/__init__.py b/wagtail/models/__init__.py index 5f316ac84347..4443d465ea78 100644 --- a/wagtail/models/__init__.py +++ b/wagtail/models/__init__.py @@ -1245,6 +1245,9 @@ class Page(AbstractPage, index.Indexed, ClusterableModel, metaclass=PageBase): # Define the maximum number of instances this page can have under a specific parent. Default to unlimited. max_count_per_parent = None + # Set the default order for child pages to be shown in the Page index listing + admin_default_ordering = "-latest_revision_created_at" + # An array of additional field names that will not be included when a Page is copied. exclude_fields_in_copy = [] default_exclude_fields_in_copy = [ @@ -1362,6 +1365,13 @@ def get_default_locale(self): return super().get_default_locale() + def get_admin_default_ordering(self): + """ + Determine the default ordering for child pages in the admin index listing. + Returns a string (e.g. 'latest_revision_created_at, title, ord' or 'live'). + """ + return self.admin_default_ordering + def full_clean(self, *args, **kwargs): # Apply fixups that need to happen before per-field validation occurs