From 8c820924fb8fcc007a8355a3cd2a487c5bae58de Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Wed, 23 Jul 2025 12:23:13 -0500 Subject: [PATCH] Fixes #18900: introduce/raise QuerySetNotOrdered exception Defines a new exception, `QuerySetNotOrdered`, and raises it in `OptionalLimitOffsetPagination.paginate_queryset` in the right conditions: - the iterable to be paginated is a QuerySet isinstance - the `queryset.ordered` flag is not truthy --- netbox/netbox/api/exceptions.py | 4 ++++ netbox/netbox/api/pagination.py | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/netbox/netbox/api/exceptions.py b/netbox/netbox/api/exceptions.py index f552b06b5..c4d05d1a5 100644 --- a/netbox/netbox/api/exceptions.py +++ b/netbox/netbox/api/exceptions.py @@ -12,3 +12,7 @@ class SerializerNotFound(Exception): class GraphQLTypeNotFound(Exception): pass + + +class QuerySetNotOrdered(Exception): + pass diff --git a/netbox/netbox/api/pagination.py b/netbox/netbox/api/pagination.py index f1430a9fd..698e0a8dd 100644 --- a/netbox/netbox/api/pagination.py +++ b/netbox/netbox/api/pagination.py @@ -1,6 +1,7 @@ from django.db.models import QuerySet from rest_framework.pagination import LimitOffsetPagination +from netbox.api.exceptions import QuerySetNotOrdered from netbox.config import get_config @@ -15,6 +16,12 @@ class OptionalLimitOffsetPagination(LimitOffsetPagination): def paginate_queryset(self, queryset, request, view=None): + if isinstance(queryset, QuerySet) and not queryset.ordered: + raise QuerySetNotOrdered( + "Paginating over an unordered queryset is unreliable. Ensure that a minimal " + "ordering has been applied to the queryset for this API endpoint." + ) + if isinstance(queryset, QuerySet): self.count = self.get_queryset_count(queryset) else: