Django中如何在get_queryset()实现列求和并在模板中访问?
Django查询集列求和:解决你的视图与模板问题
我来帮你理清这个问题——你混淆了annotate()和aggregate()的核心用法,这才导致没拿到想要的求和结果。咱们一步步拆解你的问题:
先搞懂两个方法的区别
annotate():它的作用是给查询集中的每一行数据添加一个"注释字段",通常用于分组统计(比如按类别、日期分组求和)。如果你不对查询集做分组,直接用annotate(Sum('price')),相当于给每一行都计算自己所在组(就是自己)的price总和,所以每个item的totals值其实就是它自己的price——这就是你在模板里看到每行都是单独price的原因。aggregate():它是对整个查询集做全局聚合计算,返回的是一个包含聚合结果的字典(不是查询集),用来获取整个数据集的总和、平均值这类全局统计值,这才是你想要的"某一列多行数据求和"的正确方法。
(a) 正确设置视图获取求和结果
你不需要在get_queryset()里添加总和(因为这个方法要返回查询集),而是应该把总和放到模板上下文里。分两种视图类型来说:
情况1:函数视图
# views.py from django.db.models import Sum from django.shortcuts import render from .models import ItemPrice def price_list_view(request): # 先获取过滤后的查询集 queryset = ItemPrice.objects.filter(<some_filter>) # 计算整个查询集的price总和,从返回的字典中取出值 total_price = queryset.aggregate(totals=Sum('price'))['totals'] # 把查询集和总和一起传到模板 return render(request, 'template.html', { 'object_list': queryset, 'total_price': total_price })
情况2:类视图(比如ListView)
如果是基于类的视图,重写get_context_data()来添加总和:
# views.py from django.db.models import Sum from django.views.generic import ListView from .models import ItemPrice class PriceListView(ListView): model = ItemPrice template_name = 'template.html' def get_queryset(self): # 正常返回过滤后的查询集 return ItemPrice.objects.filter(<some_filter>) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 给上下文添加总和数据 context['total_price'] = self.get_queryset().aggregate(totals=Sum('price'))['totals'] return context
(b) 模板中访问求和结果
模板里先遍历每个item的price,最后单独显示全局总和就可以了:
<!-- template.html --> <h3>所有商品价格</h3> {% for item in object_list %} <p>单价:{{ item.price }}</p> {% endfor %} <hr> <p>总价格:{{ total_price }}</p>
补充:如果需要分组求和怎么办?
要是你的需求是按某个字段分组(比如ItemPrice有category字段,要按类别统计总价),那才需要用annotate(),写法如下:
# 视图中获取分组后的查询集 queryset = ItemPrice.objects.filter(<some_filter>).values('category').annotate(category_total=Sum('price'))
模板里这样遍历:
{% for group in object_list %} <p>分类:{{ group.category }},总价:{{ group.category_total }}</p> {% endfor %}
内容的提问来源于stack exchange,提问作者Bill Armstrong
相关产品推荐
相关产品推荐

