【问题标题】:Django Annotate SumDjango注释总和
【发布时间】:2018-05-09 05:45:24
【问题描述】:

我正在尝试为查询集中包含多行的列获取简单的总和。我的直接问题是(a)我如何设置get_queryset() 以包含一列的总和以及(b)我如何在模板中访问该元素?关注this问题:

#models.py
class ItemPrice( models.Model ):
    price = models.DecimalField ( max_digits = 8, decimal_places=2 )
    ....

提供了两个答案 - 一个使用 .aggregate() 方法,我不相信它会返回一个查询集,而 .annotate() 方法我相信它会将一个项目附加到查询集。

所以,我希望以下内容会在此视图的对象列表中添加另一个项目:

#views.py
def get_queryset(self):
    # generate table and filter down to a subquery.
    queryset = ItemPrice.objects.filter(<some_filter>)
    # sum the price for each row in the subquery.
    queryset = queryset.annotate(totals=Sum('price'))
    return queryset

然后在模板中,我将能够像这样遍历对象列表:

#template.html
{% for item in object_list %}
    {{ item }}
{% endfor %}

期望其中一项(最后一项?)是price_sum,并且余额可以作为price_sum.price访问。

但是,当我将以下内容添加到我的模板时,我会得到每个行项目的价格 - 没有总和。

{% for item in object_list %}
    {{ item.totals }}
{% endfor %}

但是,我无法访问该项目。不知道是get_queryset()的视图修改问题还是模板里面的问题?

【问题讨论】:

  • 首先,您可以将两个查询结合起来,无需在两行中写入。queryset = ItemPrice.objects.filter(&lt;some_filter&gt;).annotate(totals=Sum('price')) 如果您希望显示商品的总价格,那么您可以使用模板标签。跨度>
  • 感谢@AbiWaqas,我试图遵循原始问题。我的原始代码完全按照您的建议编写 - 但它仍然没有产生我期望的 annotate(Sum) 结果。

标签: python django python-3.x


【解决方案1】:

如果要向模板添加数据

queryset = ItemPrice.objects.filter(<your_filter>)
totals = queryset.aggregate(sum=Sum('price').get('sum')

context  = {
    'object_list': queryset,
    'totals': totals,
}
render(request, '<name_of_your_template>.html', context)

在你的模板中

{% for item in object_list %}
    # price of item
    {{ item.price }}
{% endfor %}
# total price
{{ totals }}

【讨论】:

  • 这正是我试图通过get_queryset() 方法完成的——实际上它需要是get_context_data() 方法。效果很好。
【解决方案2】:

如果你会使用:

ItemPrice.objects.filter(<some_filter>).annotate(totals=Sum('price'))

totals 总是与“price”相同

注释(关于 Sum)这样的用法:

如果您有这些型号:

class ItemPrice( models.Model ):
    price = models.DecimalField ( max_digits = 8, decimal_places=2 )
    other_model = models.ForeignKey(
          to=OtherModel, 
          related_name="item_prices", 
          on_delete=models.SET_NULL
    )

# related_name - if I set related_name I can use like this
# other_model_object.item_prices.all() - this code return all 
# ItemPrices with other_model_id=other_model_object.id

class OtherModel(models.Model):
    some_field = models.CharField(max_lenght=256)

并且您想要对具有一个 OtherModel 外键的所有 ItemPrices 的所有价格,您应该使用以下代码:

queryset = OtherModel.objects.annotate(
       total_prices=Sum('item_prices__price')
).filter(<your_filters>)

之后你可以使用:

for obj in queryset:
    print(obj.total_prices)

或者如果你需要所有价格的总和,你应该使用聚合

ItemPrices.objects.aggregate(all_sum=Sum('price'))

这段代码返回字典(或类似的东西,我记不太清了) 像这样

{'all_sum': 1250}

all_sum - 数据库表中所有对象的总和

【讨论】:

  • 我想我没有意识到您必须通过带有密钥的第二个模型引用.annotate(Sum)。有没有一种简单的方法可以让view 侧代码修改queryset 以传递此信息?这似乎不是很优雅。我知道我也可以使用客户端 jQuery 类型代码 - 但希望将其保留为简单的查询集返回。
  • 我了解您的需求。你不应该使用 annotate,因为 annotate 为每个对象添加值,但你只需要一个值(而不是每个对象),如果你将这个值添加到每个对象,那就不好了。我认为最好的方法是获取两个查询,最快的是:queryset = ItemPrice.objects.filter() 和第二个:totals = queryset.aggregage(sum=Sum('price')).get('sum' ) 然后将这些数据添加到您的模板中
  • 或者你可以在python代码中求和:totals = sum((item.price for item in queryset))
  • 我认为这就是我正在寻找的 - 但我现在尝试了几种方法来组合 querysettotals 以获得单个“查询集”以返回到 @987654332 @ 方法。我错过了什么 - 似乎尝试连接(或组合)它们不起作用。
  • 不能合并,因为queryset返回的是相同的对象,但是需要返回很多相似的对象(结构),一个只有一个字段(总计)
猜你喜欢
  • 2016-10-06
  • 2020-08-24
  • 2016-01-30
  • 2019-04-07
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 2021-10-22
  • 2022-12-07
相关资源
最近更新 更多