在Django REST Framework中实现支持动态分页与django_filters兼容的API
Django REST Framework 动态分页兼容 django_filters 实现方案
核心思路
- 自定义分页类,根据请求中是否存在
offset/limit参数决定是否启用分页 - 与
django_filters结合时复用过滤后的QuerySet,避免重复执行SQL查询 - 用
exists()高效判断是否存在下一页,替代性能较差的count()
自定义动态分页类
from rest_framework.pagination import BasePagination from rest_framework.response import Response class DynamicOffsetPagination(BasePagination): def paginate_queryset(self, queryset, request, view=None): # 获取分页参数,无参数则不启用分页 offset = request.query_params.get('offset') limit = request.query_params.get('limit') if offset is None or limit is None: return None try: offset = int(offset) limit = int(limit) if offset < 0 or limit <= 0: raise ValueError except (ValueError, TypeError): # 参数不合法时返回全量数据 return None end = offset + limit self.current_offset = offset self.current_limit = limit # 仅查询下一页是否存在单条数据,避免全表count self.has_next = queryset[end:end+1].exists() return queryset[offset:end] def get_paginated_response(self, data): return Response({ 'offset': self.current_offset, 'limit': self.current_limit, 'has_next': self.has_next, 'results': data })
与django_filters结合的视图实现
假设你有模型Book、序列化器BookSerializer和过滤器BookFilter:
from django_filters.rest_framework import DjangoFilterBackend from rest_framework import viewsets from .models import Book from .serializers import BookSerializer from .filters import BookFilter class BookViewSet(viewsets.ReadOnlyModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer filter_backends = [DjangoFilterBackend] filterset_class = BookFilter pagination_class = DynamicOffsetPagination
关键细节说明
- SQL请求优化:分页逻辑复用视图过滤后的QuerySet,
exists()仅执行单条数据查询,避免全表count带来的性能损耗 - 参数容错:对
offset和limit做类型与范围校验,非法参数自动返回全量数据 - 动态切换:仅当同时提供
offset和limit时启用分页,无参数时直接返回所有结果
使用示例
- 分页请求:
GET /api/books?offset=0&limit=10
返回结构:{ "offset": 0, "limit": 10, "has_next": true, "results": [...] } - 全量请求:
GET /api/books
返回结构:[...]
内容的提问来源于stack exchange,提问作者Chanchhunneng chrea
相关产品推荐
相关产品推荐

