Page size limits and opt-in pagination behavior in Django REST Framework
0 reputation · 29 Mar 2022, 13:26 UTC
0 reputation · 29 Mar 2022, 13:26 UTC
Django REST Framework list actions return the full queryset by default. Pagination is opt-in and must be configured on a view or via REST_FRAMEWORK settings. This leaves the decision to enable pagination and choose defaults to the project author.
When PageNumberPagination is used, client-controlled page size is only possible if page_size_query_param is set, and an upper bound is only enforced if max_page_size is configured. Both options require explicit developer enablement.
LimitOffsetPagination provides offset based paging, but without max_limit set there is no built-in hard cap on the limit value a client can request. The framework intentionally does not enforce a default pagination policy, which creates an unresolved trade-off between convenience for small APIs and safety for large datasets.
What is the default enforcement behavior for max_page_size when page_size_query_param is enabled on PageNumberPagination? How does LimitOffsetPagination behave with an unbounded limit parameter when max_limit is not set? Is there a documented project-level default recommendation for pagination to balance convenience and query safety?
35275 reputation · 30 Mar 2022, 01:17 UTC
page_size_query_param enabled: max_page_size acts as a hard ceiling. If set, any client-requested page size exceeding this value is capped at max_page_size. If max_page_size is None (default), no upper bound is enforced—the client can request arbitrarily large pages.max_limit: The framework imposes no built-in cap on the limit query parameter. A client can request ?limit=1000000 and receive the entire queryset, limited only by database or memory constraints.DEFAULT_PAGINATION_CLASS in REST_FRAMEWORK settings and define bounds (max_page_size or max_limit) per view or globally.When you subclass PageNumberPagination and set page_size_query_param = 'page_size', the pagination class reads the query parameter and validates it against max_page_size.
class StandardResultsSetPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100 # hard cap
With this configuration, a request for ?page_size=500 returns 100 items. If max_page_size = None (or the attribute is omitted), the same request returns 500 items. The source logic lives in get_page_size() which calls _positive_int() with the max_page_size argument.
LimitOffsetPagination uses limit and offset parameters. The get_limit() method checks self.max_limit; if it is None, the raw integer from the query parameter is used without clamping.
class LargeResultsSetPagination(LimitOffsetPagination):
default_limit = 50
# max_limit omitted → no cap
A request for ?limit=10000 will attempt to fetch 10,000 rows. This can trigger expensive queries, memory pressure, or timeouts on large tables.
DRF treats pagination as a safety vs. convenience trade-off that varies by API:
CursorPagination) is recommended for large, ordered datasets but requires opaque cursors and stable ordering.The framework ships with DEFAULT_PAGINATION_CLASS = None, forcing an explicit opt-in. This avoids silent performance regressions when a viewset grows.
?page_size=1000 (or ?limit=1000) against a queryset of known size.len(response.data['results']) (PageNumberPagination) or len(response.data) (LimitOffsetPagination) to confirm capping or lack thereof.Are you configuring pagination globally in settings.REST_FRAMEWORK['DEFAULT_PAGINATION_CLASS'] or per-view via pagination_class? The location determines where max_page_size / max_limit must be set to take effect.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.