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

如何在Django中通过Prefetch按date分组聚合sum_weight?

解决方案

方法一:数据库层面分组(推荐,性能更优)

通过在Prefetch的查询集中使用values()按date分组,结合annotate()计算每日权重总和,同时用to_attr存储分组结果避免覆盖原关联数据。

修改查询代码:

groups = Group.objects.prefetch_related(
    Prefetch(
        "facts",
        queryset=Facts.objects.values('date').annotate(sum_weight=Sum('weight')).order_by('date'),
        to_attr='grouped_facts'
    )
)

修改序列化器:

因为grouped_facts是字典列表而非Facts实例,所以将GraphDot改为基础Serializer,并指定数据源为grouped_facts:

class GraphDot(serializers.Serializer):
    date = serializers.DateField()
    sum_weight = serializers.IntegerField()

class FoodGraphSerializer(serializers.ModelSerializer):
    dots = GraphDot(many=True, source="grouped_facts")

    class Meta:
        model = Group
        fields = ("title", "dots")
        read_only_fields = ("title", "dots")

方法二:Python层面分组(适合小数据量场景)

如果不想调整数据库查询逻辑,可以在序列化器中通过Python代码完成分组汇总:

修改序列化器:

class FoodGraphSerializer(serializers.ModelSerializer):
    dots = serializers.SerializerMethodField()

    def get_dots(self, obj):
        # 按日期分组累加权重
        date_weight_map = {}
        for fact in obj.facts.all():
            date_key = fact.date.strftime('%Y-%m-%d')
            date_weight_map[date_key] = date_weight_map.get(date_key, 0) + fact.weight
        
        # 转换为要求的结构并按日期排序
        return sorted(
            [{"date": date, "sum_weight": total} for date, total in date_weight_map.items()],
            key=lambda item: item["date"]
        )

    class Meta:
        model = Group
        fields = ("title", "dots")
        read_only_fields = ("title", "dots")

简化查询代码:

此时无需在查询中annotate,直接预取关联数据即可:

groups = Group.objects.prefetch_related("facts")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:22:26