From 8267ad0892245bf256165b5557a30c5ddc371645 Mon Sep 17 00:00:00 2001 From: Fabian Braun Date: Mon, 11 Nov 2024 08:11:53 +0100 Subject: [PATCH] Better slicing of endpoint querysets --- README.rst | 2 +- djangocms_link/admin.py | 37 +++++++++++++++++++++++++++++++------ tests/test_endpoint.py | 5 +++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 5c0511ab..5b34bea0 100644 --- a/README.rst +++ b/README.rst @@ -147,7 +147,7 @@ smaller the average result set size. The default is 0:: By default django CMS Link will paginate the search results. You can change the page size by setting the ``DJANGOCMS_LINK_PAGINATE_BY`` setting. -The default is 100:: +The default is 50:: # Show 100 results per "page" DJANGOCMS_LINK_PAGINATE_BY = 100 diff --git a/djangocms_link/admin.py b/djangocms_link/admin.py index 43a25b01..f2b10a11 100644 --- a/djangocms_link/admin.py +++ b/djangocms_link/admin.py @@ -3,8 +3,9 @@ from django.contrib import admin from django.core.exceptions import FieldError, PermissionDenied from django.db.models import OuterRef, Q, Subquery -from django.http import JsonResponse +from django.http import Http404, JsonResponse from django.urls import path +from django.utils.translation import gettext as _ from django.views.generic.list import BaseListView from cms import __version__ @@ -33,7 +34,7 @@ class GrouperModelAdmin: class AdminUrlsView(BaseListView): """Handle AutocompleteWidget's AJAX requests for data.""" - paginate_by = getattr(settings, "DJANGOCMS_LINK_PAGINATE_BY", 100) + paginate_by = getattr(settings, "DJANGOCMS_LINK_PAGINATE_BY", 50) admin_site = None def get(self, request, *args, **kwargs): @@ -54,8 +55,9 @@ def get(self, request, *args, **kwargs): if not self.has_perm(request): raise PermissionDenied - self.object_list = self.get_queryset() - self.add_admin_querysets(self.object_list) + qs_list = [self.get_queryset()] + self.add_admin_querysets(qs_list) + self.object_list = self.get_paginated_multi_qs(qs_list) context = self.get_context_data() results = self.get_optgroups(context) return JsonResponse( @@ -65,6 +67,28 @@ def get(self, request, *args, **kwargs): } ) + def get_page(self): + page_kwarg = self.page_kwarg + page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1 + try: + page_number = int(page) + except ValueError: + raise Http404( + _("Page is not “last”, nor can it be converted to an int.") + ) + return page_number + + def get_paginated_multi_qs(self, qs_list): + """ + Paginate multiple querysets and return a result list. + """ + if len(qs_list) == 1: + # Only one qs, just use regular pagination + return qs_list[0] + # Slize all querysets, evaluate and join them into a list + max_items = self.get_page() * self.paginate_by + return sum((list(qs[:max_items]) for qs in qs_list), start=[]) + def get_reference(self, request): try: model_str, pk = request.GET.get("g").split(":") @@ -113,6 +137,7 @@ def serialize_result(self, obj): "id": f"{obj._meta.app_label}.{obj._meta.model_name}:{obj.pk}", "text": getattr(obj, "__link_text__", str(obj)) or str(obj), "url": obj.get_absolute_url(), + "verbose_name": str(obj._meta.verbose_name).capitalize(), } def get_queryset(self): @@ -157,7 +182,7 @@ def get_queryset(self): ) if self.site: qs = qs.filter(node__site_id=self.site) - return list(qs) + return qs def add_admin_querysets(self, qs): for model_admin in REGISTERED_ADMIN: @@ -183,7 +208,7 @@ def add_admin_querysets(self, qs): if search_use_distinct: # pragma: no cover new_qs = new_qs.distinct() - qs += list(new_qs) + qs.append(new_qs) except Exception: # pragma: no cover # Still report back remaining urls even if one model fails pass diff --git a/tests/test_endpoint.py b/tests/test_endpoint.py index 2844e6aa..dd907329 100644 --- a/tests/test_endpoint.py +++ b/tests/test_endpoint.py @@ -44,6 +44,10 @@ def tearDown(self): self.subling.delete() def test_api_endpoint(self): + from djangocms_link import admin + + registered = admin.REGISTERED_ADMIN + admin.REGISTERED_ADMIN = [] for query_params in ("", "?app_label=1"): with self.subTest(query_params=query_params): with self.login_user_context(self.get_superuser()): @@ -65,6 +69,7 @@ def test_api_endpoint(self): _, pk = page["id"].split(":") db_page = Page.objects.get(pk=pk) self.assertEqual(page["text"], str(db_page)) + admin.REGISTERED_ADMIN = registered def test_filter(self): with self.login_user_context(self.get_superuser()):