如何在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
相关产品推荐
相关产品推荐

