如何在Django Rest Framework ModelViewSets中添加返回聚合统计值
实现方案
你只需要修改序列化器和重写视图集的list返回方法即可,无需调整查询集过滤逻辑,顺便修正你原视图get_queryset中未初始化queryset的隐患:
1. 修改serializers.py,新增外层包装序列化器
保留原有ConsumptionSerializer不变,新增一个用于包装聚合结果的序列化器:
class ConsumptionSerializer(serializers.ModelSerializer): class Meta: model = Log fields = ("water_consumption", "elec_consumption") # 新增的外层序列化器 class ConsumptionAggregateSerializer(serializers.Serializer): total_water_consumption = serializers.IntegerField() total_elec_consumption = serializers.IntegerField() detailed_logs = ConsumptionSerializer(many=True)
2. 修改views.py,修正get_queryset并重写list方法
from django.db.models import Sum class ConsumptionViewSet(viewsets.ModelViewSet): permission_classes = [permissions.IsAuthenticated, ] serializer_class = ConsumptionSerializer def get_queryset(self): # 先初始化查询集,修复原代码未定义queryset的问题 queryset = Log.objects.all() # 从URL获取查询参数 start_date = self.request.query_params.get('start_date') end_date = self.request.query_params.get('end_date') # 校验参数非空 if start_date is not None and end_date is not None: queryset = queryset.filter(date_time__range=[start_date, end_date]) return queryset else: raise ValidationError({"ERROR": ["No params found in url"]}) def list(self, request, *args, **kwargs): # 拿到过滤后的日志查询集 queryset = self.get_queryset() # 聚合计算总消耗 aggregate_result = queryset.aggregate( total_water_consumption=Sum("water_consumption"), total_elec_consumption=Sum("elec_consumption") ) # 组织返回数据结构,空查询时默认返回0避免返回null response_data = { "total_water_consumption": aggregate_result["total_water_consumption"] or 0, "total_elec_consumption": aggregate_result["total_elec_consumption"] or 0, "detailed_logs": self.get_serializer(queryset, many=True).data } # 用外层序列化器验证后返回 serializer = ConsumptionAggregateSerializer(data=response_data) serializer.is_valid(raise_exception=True) return Response(serializer.data)
可选说明
如果你只需要列表接口返回带聚合的结构,其他增删改查接口保持原有逻辑不变,上面的代码已经完全满足需求。如果需要所有接口都返回类似结构,对应重写retrieve、create等方法即可。
内容的提问来源于stack exchange,提问作者Giulia
相关产品推荐
相关产品推荐

