Configuring Client‑Controlled Page Sizes in Django REST Framework with a Hard Limit
Learn how to let API clients control page sizes in Django REST Framework while protecting your backend with a hard ceiling. This guide covers the mechanism, a concrete example, and common pitfalls to avoid.
19 Oct 2025, 14:28 UTC

Why You Need a Hard Ceiling
When an API lets clients decide how many items to fetch per page, the page_size query parameter is convenient. However, without a hard upper bound the client could request thousands of records in a single call, leading to slow database queries, large memory usage, and bloated responses that strain both the server and the client.
How PageNumberPagination Works
The PageNumberPagination class in DRF handles two distinct query parameters:
page– selects which page of results to return.page_size– (optional) overrides the default page size for that request.
Internally the paginator calculates offset = (page - 1) * page_size and slices the queryset accordingly. The response is wrapped in an envelope containing count, next, previous, and results.
Concrete Example: Enabling Adjustable Page Size
Below is a minimal, reproducible setup that demonstrates how to expose page_size to clients while protecting the API with max_page_size.
# settings.py
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 25, # Default if client does not specify
"PAGE_SIZE_QUERY_PARAM": "page_size", # Query param name
"MAX_PAGE_SIZE": 100, # Hard ceiling
"PAGE_QUERY_PARAM": "page", # Query param name for page number
}
With the above configuration, a client can hit /api/items/?page=2&page_size=30 to receive 30 items per page, up to the 100‑item limit. If a client requests page_size=200, DRF will cap the response to 100 items.
For a view‑specific override:
# views.py
from rest_framework.generics import ListAPIView
from rest_framework.pagination import PageNumberPagination
class CustomPagination(PageNumberPagination):
page_size = 15
page_size_query_param = "size"
max_page_size = 50
page_query_param = "p"
class ItemListView(ListAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
pagination_class = CustomPagination
Now the endpoint accepts ?p=1&size=20 but will never return more than 50 items.
Common Pitfalls and Best Practices
- Missing
max_page_size: Without this, a client can request an arbitrarily large page. Always set a sensible ceiling that matches your database and memory constraints. - Renaming query parameters: Changing
page_query_paramorpage_size_query_parambreaks existing client calls that rely on the default names. If you must rename, update client documentation and test the new URLs. - Pagination not applied: DRF only paginates if either
DEFAULT_PAGINATION_CLASSis defined in settings orpagination_classis set on the view. Verify by inspectingview.pagination_classor by inspecting the response envelope. - Large
PAGE_SIZEdefaults: A global default of 1000+ can still cause problems if a client omitspage_size. Keep the default modest (e.g., 25–50) and rely onmax_page_sizefor safety.
Verifying Your Configuration
- Start the Django development server.
- Call an endpoint that uses pagination, e.g.,
curl "http://localhost:8000/api/items/?page=1&page_size=10". - Inspect the JSON response – it should include
count,next,previous, and an array ofresultswith exactly 10 items. - Request a page size larger than
max_page_sizeand confirm the response contains at mostmax_page_sizeitems. - Check the view’s
pagination_classattribute in the Django shell:python manage.py shell > from myapp.views import ItemListView > print(ItemListView.pagination_class).
By following these steps you can confidently expose flexible pagination to clients while safeguarding your API’s performance.
Limitations
PageNumberPagination only supports simple page numbers. If you need cursor‑based pagination for deep scrolling or consistent ordering, consider CursorPagination instead. Also, the hard limit is enforced server‑side; clients may still experience slower responses if the limit is set too high, so choose max_page_size carefully.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.