CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-djangorestframework

Web APIs for Django, made easy.

Pending
Overview
Eval results
Files

pagination-filtering.mddocs/

Pagination and Filtering

Built-in pagination styles and filtering backends for managing large datasets with search and ordering capabilities in Django REST Framework.

Capabilities

Pagination Classes

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
        """

Filter Backend Classes

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
        """

Usage Examples

Basic Pagination Setup

# 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 = CustomPagination

Limit/Offset Pagination

from 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=50

Cursor Pagination for Large Datasets

from 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%3D

Search and Filtering

from 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=^beginning

Custom Filter Backend

from 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']

Advanced Search Configuration

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=-title

Custom Pagination Response Format

from 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
        })

Utility Functions

# 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

docs

auth-permissions.md

content-negotiation.md

decorators.md

fields-validation.md

generic-views.md

index.md

pagination-filtering.md

request-response.md

routers-urls.md

serializers.md

status-exceptions.md

testing.md

views-viewsets.md

tile.json