Django API Pagination
Breaking large datasets into manageable pages
📄 What is API Pagination?
Pagination divides large API responses into smaller pages, improving performance and user experience. Instead of loading thousands of records at once, you get manageable chunks of data.
# Simple pagination example
from rest_framework.pagination import PageNumberPagination
class StandardPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 100
Types of Pagination
PageNumberPagination
Navigate using page numbers (1, 2, 3...)
LimitOffsetPagination
Control limit and offset manually
CursorPagination
Best for large datasets with cursor
Custom Pagination
Create your own pagination style
🔹 Setting Up PageNumberPagination
PageNumberPagination is the most common pagination style. It divides results into numbered pages, making it easy for users to navigate through data like browsing a book.
# pagination.py
from rest_framework.pagination import PageNumberPagination
class CustomPagination(PageNumberPagination):
page_size = 10 # Items per page
page_size_query_param = 'page_size' # Allow client to set page size
max_page_size = 100 # Maximum items per page
# views.py
from rest_framework import generics
from .models import Product
from .serializers import ProductSerializer
from .pagination import CustomPagination
class ProductListView(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = CustomPagination
API Response:
{
"count": 100,
"next": "http://api.example.com/products/?page=2",
"previous": null,
"results": [
{"id": 1, "name": "Product 1"},
{"id": 2, "name": "Product 2"},
...
]
}
🔹 LimitOffsetPagination
LimitOffsetPagination gives you precise control over which records to fetch. Use 'limit' to specify how many items and 'offset' to skip records, perfect for custom navigation.
# pagination.py
from rest_framework.pagination import LimitOffsetPagination
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 10
max_limit = 50
# views.py
class ProductListView(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = CustomLimitOffsetPagination
# Usage:
# GET /products/?limit=10&offset=20
# Returns 10 items starting from item 21
Query Parameters:
- limit: Number of items to return
- offset: Number of items to skip
- Example: ?limit=5&offset=10 (items 11-15)
🔹 CursorPagination
CursorPagination is ideal for large, frequently updated datasets. It uses a cursor (pointer) to track position, ensuring consistent results even when data changes, preventing duplicate or missing items.
# pagination.py
from rest_framework.pagination import CursorPagination
class ProductCursorPagination(CursorPagination):
page_size = 10
ordering = '-created_at' # Must specify ordering
# views.py
class ProductListView(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = ProductCursorPagination
Benefits:
- ✅ No duplicate results
- ✅ Consistent pagination
- ✅ Better performance for large datasets
- ❌ Cannot jump to specific page
🔹 Global Pagination Settings
Set default pagination for all API views in your Django settings file:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
# This applies to all views unless overridden
🔹 Custom Pagination Class
Create custom pagination to match your specific API requirements and response format:
# pagination.py
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class CustomPagination(PageNumberPagination):
page_size = 10
def get_paginated_response(self, data):
return Response({
'total_items': self.page.paginator.count,
'total_pages': self.page.paginator.num_pages,
'current_page': self.page.number,
'next': self.get_next_link(),
'previous': self.get_previous_link(),
'data': data
})