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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 00:24:01