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,提问作者Александр Демидов
相关产品推荐
相关产品推荐

