From 1c65a1bb0e6a5d60c8f5b84ca49e6e8b9c89de7b Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 11 Mar 2026 23:53:27 -0700 Subject: [PATCH] Backend deprecate all to only api v < 10 --- src/documents/index.py | 20 ++++++++++++++++++++ src/documents/views.py | 5 +++-- src/paperless/views.py | 42 ++++++++++++++++++++++++++++-------------- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/documents/index.py b/src/documents/index.py index 3a3b59e37..02e894472 100644 --- a/src/documents/index.py +++ b/src/documents/index.py @@ -375,6 +375,26 @@ class DelayedQuery: ] return self._manual_hits_cache + def get_result_ids(self) -> list[int]: + """ + Return all matching document IDs for the current query and ordering. + """ + if self._manual_sort_requested(): + return [hit["id"] for hit in self._manual_hits()] + + q, mask, suggested_correction = self._get_query() + self.suggested_correction = suggested_correction + sortedby, reverse = self._get_query_sortedby() + results = self.searcher.search( + q, + mask=mask, + filter=MappedDocIdSet(self.filter_queryset, self.searcher.ixreader), + limit=None, + sortedby=sortedby, + reverse=reverse, + ) + return [hit["id"] for hit in results] + def __getitem__(self, item): if item.start in self.saved_results: return self.saved_results[item.start] diff --git a/src/documents/views.py b/src/documents/views.py index 7d89e6faf..2a4aa3cc2 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -555,7 +555,8 @@ class TagViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet): page = self.paginate_queryset(queryset) serializer = self.get_serializer(page, many=True) response = self.get_paginated_response(serializer.data) - if descendant_pks: + api_version = int(request.version or settings.REST_FRAMEWORK["DEFAULT_VERSION"]) + if descendant_pks and api_version < 10: # Include children in the "all" field, if needed response.data["all"] = [tag.pk for tag in children_source] return response @@ -2084,7 +2085,7 @@ class UnifiedSearchViewSet(DocumentViewSet): ), ), ): - result_ids = response.data.get("all", []) + result_ids = queryset.get_result_ids() response.data["selection_data"] = ( self._get_selection_data_for_queryset( Document.objects.filter(pk__in=result_ids), diff --git a/src/paperless/views.py b/src/paperless/views.py index 05a0997fb..72917ffca 100644 --- a/src/paperless/views.py +++ b/src/paperless/views.py @@ -9,6 +9,7 @@ from allauth.mfa.recovery_codes.internal.flows import auto_generate_recovery_cod from allauth.mfa.totp.internal import auth as totp_auth from allauth.socialaccount.adapter import get_adapter from allauth.socialaccount.models import SocialAccount +from django.conf import settings from django.contrib.auth.models import Group from django.contrib.auth.models import User from django.contrib.staticfiles.storage import staticfiles_storage @@ -56,17 +57,27 @@ class StandardPagination(PageNumberPagination): page_size_query_param = "page_size" max_page_size = 100000 + def _get_api_version(self) -> int: + request = getattr(self, "request", None) + default_version = settings.REST_FRAMEWORK["DEFAULT_VERSION"] + return int(request.version if request else default_version) + + def _should_include_all(self) -> bool: + # TODO: remove legacy `all` support when API v9 is dropped. + return self._get_api_version() < 10 + def get_paginated_response(self, data): + response_data = [ + ("count", self.page.paginator.count), + ("next", self.get_next_link()), + ("previous", self.get_previous_link()), + ] + if self._should_include_all(): + response_data.append(("all", self.get_all_result_ids())) + response_data.append(("results", data)) + return Response( - OrderedDict( - [ - ("count", self.page.paginator.count), - ("next", self.get_next_link()), - ("previous", self.get_previous_link()), - ("all", self.get_all_result_ids()), - ("results", data), - ], - ), + OrderedDict(response_data), ) def get_all_result_ids(self): @@ -87,11 +98,14 @@ class StandardPagination(PageNumberPagination): def get_paginated_response_schema(self, schema): response_schema = super().get_paginated_response_schema(schema) - response_schema["properties"]["all"] = { - "type": "array", - "example": "[1, 2, 3]", - "items": {"type": "integer"}, - } + if self._should_include_all(): + response_schema["properties"]["all"] = { + "type": "array", + "example": "[1, 2, 3]", + "items": {"type": "integer"}, + } + else: + response_schema["properties"].pop("all", None) return response_schema