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

如何在Django REST Framework中序列化分组聚合后的Metric记录

实现方案

第一步:新增聚合结果序列化器

原有MetricSerializer是匹配单条业务明细数据的,聚合后的结果没有原模型的主键等字段,需要新增专用的聚合序列化器:

from rest_framework import serializers

class MetricAggregationSerializer(serializers.Serializer):
    # 固定聚合指标字段
    impressions = serializers.IntegerField()
    clicks = serializers.IntegerField()
    # 可选分组字段,设置为非必填适配不同分组请求
    date = serializers.DateField(required=False)
    channel = serializers.CharField(required=False)
    country = serializers.CharField(required=False)
    os = serializers.CharField(required=False)

第二步:重写ViewSet逻辑实现动态分组聚合

修改原有MetricViewSet,支持接收分组参数,先执行过滤规则再做聚合计算:

from django.db.models import Sum
from rest_framework.response import Response

class MetricViewSet(viewsets.ModelViewSet):
    serializer_class = MetricSerializer
    queryset = Metric.objects.all()
    filter_backends = [DjangoFilterBackend]
    filterset_class = MetricFilter

    def get_serializer_class(self):
        # 列表查询带分组参数时使用聚合序列化器
        if self.action == 'list' and self.request.query_params.get('group_by'):
            return MetricAggregationSerializer
        return super().get_serializer_class()

    def list(self, request, *args, **kwargs):
        group_by_fields = request.query_params.get('group_by', None)
        # 未传分组参数走原有逻辑返回明细数据
        if not group_by_fields:
            return super().list(request, *args, **kwargs)
        
        # 分组字段白名单校验,避免非法字段注入风险
        allowed_group_fields = {'date', 'channel', 'country', 'os'}
        group_fields = [f.strip() for f in group_by_fields.split(',') if f.strip() in allowed_group_fields]
        if not group_fields:
            return Response({"error": "仅支持date、channel、country、os作为分组字段"}, status=400)
        
        # 先应用已有过滤规则(比如示例中的日期过滤会自动生效)
        queryset = self.filter_queryset(self.get_queryset())
        # 执行分组聚合逻辑
        queryset = queryset.values(*group_fields).annotate(
            impressions=Sum('impressions'),
            clicks=Sum('clicks')
        ).order_by('-clicks') # 可根据需求调整为动态排序规则

        # 序列化返回结果
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

使用方式

要实现你示例中按channel、country分组、日期小于2017-06-01的查询效果,直接请求如下接口即可:
GET /metric/?group_by=channel,country&date__lt=2017-06-01
返回结果和你给出的SQL执行效果完全一致。

可选优化

如果需要动态调整排序规则,可以额外接收sort参数,替换代码中固定的order_by('-clicks')逻辑即可适配更多场景。

内容的提问来源于stack exchange,提问作者Jebaseelan Ravi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 23:09:04