Web APIs for Django, made easy.
—
Built-in pagination styles and filtering backends for managing large datasets with search and ordering capabilities in Django REST Framework.
Pagination classes for breaking large datasets into manageable chunks.
class BasePagination:
"""
Base class for all pagination implementations.
"""
display_page_controls = False
template = None
def paginate_queryset(self, queryset, request, view=None):
"""
Paginate a queryset and return a page of results.
Args:
queryset: QuerySet to paginate
request: Current request object
view: View handling the request
Returns:
list or None: Page of results or None if pagination not applied
"""
def get_paginated_response(self, data):
"""
Return paginated response for given data.
Args:
data: Serialized page data
Returns:
Response: Paginated response with metadata
"""
def get_paginated_response_schema(self, schema):
"""
Return schema for paginated response.
Args:
schema: Schema for individual items
Returns:
dict: Complete paginated response schema
"""
class PageNumberPagination(BasePagination):
"""
Page number-based pagination (page=1, page=2, etc.).
"""
page_size = 20 # Default page size
page_query_param = 'page' # URL parameter for page number
page_size_query_param = None # URL parameter for custom page size
max_page_size = None # Maximum allowed page size
last_page_strings = ('last',) # Strings accepted for last page
template = 'rest_framework/pagination/numbers.html'
def get_page_size(self, request):
"""
Get page size from request or use default.
Args:
request: Current request object
Returns:
int: Page size to use
"""
class LimitOffsetPagination(BasePagination):
"""
Limit/offset pagination (limit=20&offset=40).
"""
default_limit = 20 # Default number of results per page
limit_query_param = 'limit' # URL parameter for limit
offset_query_param = 'offset' # URL parameter for offset
max_limit = None # Maximum allowed limit
template = 'rest_framework/pagination/numbers.html'
def get_limit(self, request):
"""
Get limit from request or use default.
Args:
request: Current request object
Returns:
int: Limit to use
"""
class CursorPagination(BasePagination):
"""
Cursor-based pagination for large datasets with consistent ordering.
"""
cursor_query_param = 'cursor' # URL parameter for cursor
cursor_query_description = 'The pagination cursor value.'
page_size = 20 # Default page size
invalid_cursor_message = 'Invalid cursor'
ordering = None # Required: field(s) to order by
template = 'rest_framework/pagination/previous_and_next.html'
def get_ordering(self, request, queryset, view):
"""
Get ordering for cursor pagination.
Args:
request: Current request object
queryset: QuerySet being paginated
view: View handling request
Returns:
tuple: Ordering fields
"""Backend classes for filtering, searching, and ordering querysets.
class BaseFilterBackend:
"""
Base class for filter backends.
"""
def filter_queryset(self, request, queryset, view):
"""
Filter the queryset based on request parameters.
Args:
request: Current request object
queryset: QuerySet to filter
view: View handling request
Returns:
QuerySet: Filtered queryset
"""
raise NotImplementedError
def get_schema_fields(self, view):
"""
Get schema fields for this filter backend.
Args:
view: View using this backend
Returns:
list: List of schema fields
"""
return []
def get_schema_operation_parameters(self, view):
"""
Get OpenAPI operation parameters for this backend.
Args:
view: View using this backend
Returns:
list: List of parameter definitions
"""
return []
class SearchFilter(BaseFilterBackend):
"""
Filter that supports text search across specified fields.
"""
search_param = 'search' # URL parameter for search terms
template = 'rest_framework/filters/search.html'
lookup_prefixes = {
'^': 'istartswith',
'=': 'iexact',
'@': 'search',
'$': 'iregex',
}
search_title = 'Search'
search_description = 'A search term.'
def get_search_fields(self, view, request):
"""
Get fields to search across from view configuration.
Args:
view: View with search_fields attribute
request: Current request object
Returns:
list: Field names to search
"""
def get_search_terms(self, request):
"""
Extract search terms from request parameters.
Args:
request: Current request object
Returns:
list: Search terms
"""
def construct_search(self, field_name, queryset):
"""
Construct database search for field.
Args:
field_name (str): Field to search with lookup prefix
queryset: QuerySet being filtered
Returns:
Q: Django Q object for search
"""
class OrderingFilter(BaseFilterBackend):
"""
Filter that supports ordering results by specified fields.
"""
ordering_param = 'ordering' # URL parameter for ordering
ordering_fields = None # Allowed ordering fields
ordering_title = 'Ordering'
ordering_description = 'Which field to use when ordering the results.'
template = 'rest_framework/filters/ordering.html'
def get_ordering(self, request, queryset, view):
"""
Get ordering fields from request parameters.
Args:
request: Current request object
queryset: QuerySet being ordered
view: View handling request
Returns:
list or None: Ordering field names
"""
def get_default_ordering(self, view):
"""
Get default ordering from view configuration.
Args:
view: View with ordering attribute
Returns:
list or None: Default ordering fields
"""
def get_valid_fields(self, queryset, view, context=None):
"""
Get fields that are valid for ordering.
Args:
queryset: QuerySet being ordered
view: View handling request
context: Additional context
Returns:
list: Valid field names for ordering
"""# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20
}
# View-level pagination
from rest_framework.pagination import PageNumberPagination
class CustomPagination(PageNumberPagination):
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 100
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = CustomPaginationfrom rest_framework.pagination import LimitOffsetPagination
class CustomLimitOffsetPagination(LimitOffsetPagination):
default_limit = 25
limit_query_param = 'limit'
offset_query_param = 'offset'
max_limit = 100
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = CustomLimitOffsetPagination
# Client usage:
# GET /api/books/?limit=25&offset=50from rest_framework.pagination import CursorPagination
class BookCursorPagination(CursorPagination):
page_size = 20
ordering = '-created_at' # Required for cursor pagination
cursor_query_param = 'cursor'
page_size_query_param = 'page_size'
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = BookCursorPagination
# Client usage:
# GET /api/books/?cursor=cD0yMDIzLTEwLTE1KzAwJTNBMDA%3Dfrom rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
# Exact field filtering
filterset_fields = ['genre', 'publication_year', 'author']
# Text search across fields
search_fields = ['title', 'author__name', '=isbn'] # = for exact match
# Ordering options
ordering_fields = ['title', 'publication_date', 'author__name']
ordering = ['-publication_date'] # Default ordering
# Client usage:
# GET /api/books/?genre=fiction&search=django&ordering=title
# GET /api/books/?publication_year=2023&search=^beginningfrom rest_framework.filters import BaseFilterBackend
class AuthorCountryFilter(BaseFilterBackend):
"""
Filter books by author's country.
"""
def filter_queryset(self, request, queryset, view):
country = request.query_params.get('author_country')
if country:
queryset = queryset.filter(author__country__iexact=country)
return queryset
def get_schema_fields(self, view):
return [
coreapi.Field(
name='author_country',
location='query',
required=False,
type='string',
description='Filter by author country'
)
]
class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [AuthorCountryFilter, SearchFilter]
search_fields = ['title', 'author__name']class BookListView(ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [SearchFilter, OrderingFilter]
# Advanced search field configuration
search_fields = [
'title', # icontains (default)
'^author__name', # istartswith
'=isbn', # iexact
'@description', # Full-text search (PostgreSQL)
'$genre', # iregex
]
# Restrict ordering to specific fields
ordering_fields = ['title', 'publication_date']
ordering = ['-publication_date', 'title']
# Client usage:
# GET /api/books/?search=python+programming&ordering=-titlefrom rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class CustomPageNumberPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
def get_paginated_response(self, data):
return Response({
'pagination': {
'next': self.get_next_link(),
'previous': self.get_previous_link(),
'count': self.page.paginator.count,
'page_number': self.page.number,
'num_pages': self.page.paginator.num_pages,
'page_size': self.get_page_size(self.request)
},
'results': data
})# Internal pagination utilities
def _positive_int(integer_string, strict=False, cutoff=None):
"""
Parse positive integer from string.
Args:
integer_string (str): String to parse
strict (bool): Require positive integer
cutoff (int): Maximum allowed value
Returns:
int: Parsed integer
Raises:
ValueError: If invalid integer
"""
def _divide_with_ceil(a, b):
"""
Division with ceiling (for page calculations).
Args:
a (int): Dividend
b (int): Divisor
Returns:
int: Ceiling division result
"""
# Search utilities
def search_smart_split(search_terms):
"""
Smart split search terms respecting quoted phrases.
Args:
search_terms (str): Raw search string
Returns:
list: Split search terms preserving quoted phrases
"""Install with Tessl CLI
npx tessl i tessl/pypi-djangorestframework