如何为Django Rest Framework的ViewSet实现POST响应分页?
实现Django Rest Framework ViewSet POST接口的分页
针对你用ViewSet基类编写的POST接口,DRF默认分页机制主要针对list方法,但我们可以手动实现适配POST场景的分页逻辑,具体步骤如下:
1. 配置分页类(全局/局部二选一)
首先需要指定要使用的分页规则,有两种配置方式:
- 全局配置:在项目
settings.py中添加DRF的全局分页设置:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10 # 默认每页展示10条数据 }
- 局部配置:直接在你的
FilterProductsViewSet中单独指定:
from rest_framework import pagination class FilterProductsViewSet(viewsets.ViewSet): permission_classes = (permissions.IsAuthenticated,) pagination_class = pagination.PageNumberPagination
2. 修改POST方法实现分页逻辑
ViewSet基类没有内置POST方法的分页处理,我们需要手动实例化分页器、处理数据并返回标准分页响应:
from rest_framework import pagination, permissions, viewsets from rest_framework.response import Response from django.db import transaction from inventory.models import Product, Stock # 导入你对应的产品序列化器(如果还没有,需要先定义) from inventory.serializers import ProductSerializer class FilterProductsViewSet(viewsets.ViewSet): permission_classes = (permissions.IsAuthenticated,) pagination_class = pagination.PageNumberPagination @transaction.atomic def post(self, request): # 1. 获取过滤后的查询集(建议让get_filter返回QuerySet而非列表,性能更优) queryset = get_filter(request.data, len(request.data)) # 2. 实例化分页器并处理查询集 paginator = self.pagination_class() paginated_data = paginator.paginate_queryset(queryset, request) # 3. 序列化分页后的结果 serializer = ProductSerializer(paginated_data, many=True) # 4. 返回带分页元信息的响应(包含count/next/previous/results四个字段) return paginator.get_paginated_response(serializer.data)
特殊场景处理:如果get_filter返回的是普通列表
如果你的get_filter函数返回的是普通Python列表而非QuerySet,上面的分页器无法直接处理,这时可以自定义一个兼容列表的分页类:
class ListCompatiblePagination(pagination.PageNumberPagination): def paginate_queryset(self, queryset, request, view=None): # 兼容列表类型的数据源 self.page_size = self.get_page_size(request) if not self.page_size: return None paginator = self.django_paginator_class(queryset, self.page_size) page_number = request.query_params.get(self.page_query_param, 1) # 处理"last"这类特殊页码标识 if page_number in self.last_page_strings: page_number = paginator.num_pages try: self.page = paginator.page(page_number) except (paginator.InvalidPage, ValueError) as exc: from rest_framework.exceptions import NotFound raise NotFound(self.invalid_page_message.format(exc=exc)) if paginator.num_pages > 1 and self.template is not None: self.display_page_controls = True self.request = request return list(self.page)
之后把ViewSet的pagination_class替换成这个自定义类即可。
前端请求时,可以通过page参数指定页码(比如?page=2),如果配置了PAGE_SIZE_QUERY_PARAM,还支持用户自定义每页数量(比如?page=1&page_size=20)。
内容的提问来源于stack exchange,提问作者HuLu ViCa
相关产品推荐
相关产品推荐

