如何在Django REST Framework ModelViewSet列表返回外层添加额外字段?
实现方案
最优方案是重写SaleViewSet的list方法,在原有响应结构的基础上插入聚合字段,既适配你现有代码逻辑,也能保证聚合范围和返回的查询结果一致,实现成本最低。
具体实现步骤
- 先导入需要的聚合函数:
from django.db.models import Min, Max
- 在
SaleViewSet类中添加重写的list方法:
def list(self, request, *args, **kwargs): # 获取经过权限校验、过滤、排序后的完整查询集 queryset = self.filter_queryset(self.get_queryset()) # 单次查询同时获取最小、最大值,避免两次数据库请求 aggregate_result = queryset.aggregate( min_total=Min("total"), max_total=Max("total") ) # 原有分页逻辑 page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) # 拿到原有分页响应的顶层数据,插入聚合字段 paginated_data = self.get_paginated_response(serializer.data).data paginated_data.update(aggregate_result) return Response(paginated_data) # 兼容未开启分页的场景 serializer = self.get_serializer(queryset, many=True) return Response({ "results": serializer.data, **aggregate_result })
优化点说明
- 聚合范围准确:使用经过
filter_queryset处理后的查询集做聚合,保证min_total、max_total和当前返回的results属于同一数据范围,适配权限校验、用户传的过滤参数,不会出现返回的是当前用户的销售数据,聚合的却是全表数据的问题 - 查询效率高:一次
aggregate查询同时取两个聚合值,比两次单独查询减少一次数据库IO - 兼容性强:同时适配分页/非分页场景,不需要修改现有分页器、序列化类,逻辑内聚在列表接口逻辑中
- 可适配缓存:如果需要和现有缓存逻辑对齐,可以把聚合结果也按相同规则缓存,减少数据库压力:
# 复用你原有生成cache_key的逻辑 if request.user.is_staff: cache_agg_key = 'list_sale_sales_agg' else: cache_agg_key = f'list_sale_sales_client_{request.user.profil.client.pk}_agg' aggregate_result = cache.get(cache_agg_key) if not aggregate_result: aggregate_result = queryset.aggregate(min_total=Min("total"), max_total=Max("total")) cache.set(cache_agg_key, aggregate_result, 60)
内容的提问来源于stack exchange,提问作者darkvodka
相关产品推荐
相关产品推荐

