python / expert
Snippet
Django REST Framework Nested Resource Pagination with Cursor-Based Strategy
This pagination class extends Django REST Framework's PageNumberPagination with cursor-based navigation for nested resources. It provides consistent pagination regardless of data changes between requests, supports variable page sizes, and includes metadata about remaining items. The cursor approach prevents page drift when underlying data is modified during paginated traversal.
snippet.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from rest_framework.pagination import PageNumberPaginationfrom rest_framework.response import Responsefrom collections import OrderedDictclass NestedResourcePagination(PageNumberPagination):page_size = 20page_size_query_param = 'page_size'max_page_size = 100cursor_query_param = 'cursor'def __init__(self):super().__init__()self.current_cursor = Nonedef get_page_size(self, request):if 'cursor' in request.query_params:return self.max_page_sizereturn super().get_page_size(request)def get_paginated_response(self, data, parent_context=None):return Response(OrderedDict([('count', self.page.paginator.count),('next', self.get_next_link()),('previous', self.get_previous_link()),('cursor', self.current_cursor),('results', data),('metadata', self.build_metadata(parent_context))]))def get_paginated_response_schema(self, schema):return {'type': 'object','properties': {'count': {'type': 'integer', 'description': 'Total number of results'},'next': {'type': 'string', 'nullable': True, 'format': 'uri'},'previous': {'type': 'string', 'nullable': True, 'format': 'uri'},'cursor': {'type': 'string', 'description': 'Opaque cursor for next page'},'results': schema,'metadata': {'type': 'object','properties': {'total_pages': {'type': 'integer'},'has_more': {'type': 'boolean'},'remaining_count': {'type': 'integer'}}}}}def build_metadata(self, parent_context):if not parent_context:return {}return OrderedDict([('total_pages', self.page.paginator.num_pages),('has_more', self.page.has_next(),('remaining_count', self.page.paginator.count - self.page.end_index()))])
django
Breakdown
1
class NestedResourcePagination(PageNumberPagination)
Extends PageNumberPagination to support both offset and cursor-based pagination modes
2
cursor_query_param = 'cursor'
Defines query parameter name for cursor-based pagination requests
3
def get_page_size(self, request)
Returns max page size when cursor is present to optimize cursor-based queries
4
return Response(OrderedDict([('cursor', self.current_cursor), ...]))
Returns paginated response with opaque cursor for stateless client-side navigation
5
build_metadata(self, parent_context)
Constructs metadata dictionary with total pages and remaining count for UI display