Configuring PageNumberPagination to raise 404 for out‑of‑range page requests
0 reputation · 29 Jun 2026, 12:59 UTC
0 reputation · 29 Jun 2026, 12:59 UTC
Goal: Ensure that a DRF view using PageNumberPagination returns an HTTP 404 response when a client requests a page number that exceeds the total number of pages, instead of an empty results set.
Constraints: The current implementation returns count 0 and an empty results list without raising an exception, and there is no documented setting to change this behavior. Deciding whether to enforce a 404 globally, per view, or via a custom pagination subclass involves trade‑offs with client expectations and existing API contracts.
35775 reputation · 29 Jun 2026, 16:18 UTC
Django REST Framework (DRF) does not provide a built-in setting to return a 404 response when a requested page number exceeds the total number of available pages. By default, PageNumberPagination returns an empty results list and a 200 OK status.
To enforce a 404 response, you must subclass PageNumberPagination and override the paginate_queryset method. This allows you to validate the requested page against the total count before the queryset is sliced.
from django.http import Http404
from rest_framework.pagination import PageNumberPagination
class StrictPageNumberPagination(PageNumberPagination):
def paginate_queryset(self, queryset, request, view=None):
self.request = request
self.page_size = self.page_size or view.pagination_class.page_size
# Calculate total pages
count = queryset.count()
self.count = count
# Extract requested page number
page_number = request.query_params.get(self.page_query_param)
if page_number:
try:
page_number = int(page_number)
# Calculate total pages based on page_size
import math
total_pages = math.ceil(count / self.page_size)
if page_number > total_pages:
raise Http404("Page not found")
except (ValueError, TypeError):
# Let the base class handle invalid non-integer page numbers
pass
return super().paginate_queryset(queryset, request, view)
You can apply this behavior in two ways depending on your API contract requirements:
pagination_class = StrictPageNumberPagination within a specific ViewSet or APIView.REST_FRAMEWORK settings in settings.py:
'DEFAULT_PAGINATION_CLASS': 'path.to.StrictPageNumberPagination'.Implementing this check affects the API in the following ways:
count, next, and previous links remain unchanged as the base paginate_queryset logic is still executed..count() query on every request. While standard for PageNumberPagination, it can be a bottleneck on extremely large tables without proper indexing.?page=1) and verify a 200 OK response with full metadata.?page=9999) and verify the response is 404 Not Found.?page=abc) to ensure the default DRF error handling for invalid parameters still functions.Diagnostic Detail: Are you using a custom page_size_query_param that allows clients to override the page size? If so, the total_pages calculation must use the dynamic page size from the request instead of the class default.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.