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

DRF ViewSet中如何调用分页方法并扩展分页响应字段?

DRF ViewSet分页响应添加额外字段并保留分页链接

问题诊断

你的代码存在以下问题导致分页链接无法正确生成:

  • 分页场景下序列化了完整的queryset而非分页后的page,既返回了全量数据,也丢失了分页上下文
  • 直接调用pagination_class的类方法get_next_link,而非使用已初始化的分页实例(该实例包含当前请求的分页参数与上下文)
  • 错误地对序列化后的data调用paginate_queryset,该方法仅支持处理数据库查询集(QuerySet类型)

修正后的代码实现

from django.db.models import Count, Q
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet
from rest_framework.pagination import PageNumberPagination
from collections import OrderedDict

class VpsViewSet(GenericViewSet):
    pagination_class = PageNumberPagination
    queryset = Vps.objects.all()
    serializer_class = VpsSerializer  # 替换为你的实际序列化器

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        
        # 统一查询状态统计,避免分页/不分页场景重复执行DB查询
        status_count = Vps.objects.all().aggregate(
            started=Count("status", filter=Q(status="started")),
            blocked=Count("status", filter=Q(status="blocked")),
            stopped=Count("status", filter=Q(status="stopped"))
        )

        page = self.paginate_queryset(queryset)
        if page is not None:
            # 序列化分页后的page,而非完整queryset
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data, status_count)
        else:
            serializer = self.get_serializer(queryset, many=True)
            status_count["results"] = serializer.data
            return Response(status_count)

    def get_paginated_response(self, data, status_count):
        # 复用DRF原生分页响应结构,添加自定义字段
        paginated_data = super().get_paginated_response(data).data
        # 将状态统计字段合并到分页响应中
        paginated_data.update(status_count)
        return Response(paginated_data)

    # 如果你需要自定义分页响应的字段顺序,可替换为以下实现:
    # def get_paginated_response(self, data, status_count):
    #     return Response(OrderedDict([
    #         ('count', self.paginator.page.paginator.count),
    #         ('next', self.paginator.get_next_link()),
    #         ('previous', self.paginator.get_previous_link()),
    #         ('started', status_count["started"]),
    #         ('blocked', status_count["blocked"]),
    #         ('stopped', status_count["stopped"]),
    #         ('results', data)
    #     ]))

关键改动说明

  • 复用统计查询:在list方法开头统一查询状态统计,避免分页和不分页场景下重复执行数据库查询,提升性能
  • 序列化分页数据:分页时对page(而非完整queryset)进行序列化,确保返回当前页的正确数据
  • 使用内置分页实例:调用paginate_queryset后,self.paginator已自动初始化,直接调用其get_next_link()和get_previous_link()方法即可生成正确的分页链接
  • 合并自定义字段:通过update方法将统计字段合并到DRF原生分页响应中,或手动构建OrderedDict自定义字段顺序

内容的提问来源于stack exchange,提问作者Александр Демидов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 02:15:35