You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 13:32:46