Django annotate和values():'group by'中的额外字段会导致意外结果

时间:2022-09-11 17:48:49

I must be missing something obvious, as the behavior is not as expected for this simple requirement. Here is my model class:

我必须遗漏一些明显的东西,因为这个简单的要求的行为并不像预期的那样。这是我的模型类:

class Encounter(models.Model):
    activity_type = models.CharField(max_length=2, 
                           choices=(('ip','ip'), ('op','op'), ('ae', 'ae')))
    cost = models.DecimalField(max_digits=8, decimal_places=2)

I want to find the total cost for each activity type. My query is:

我想找到每种活动类型的总费用。我的查询是:

>>> Encounter.objects.values('activity_type').annotate(Sum('cost'))

Which yields:

产量:

>>> [{'cost__sum': Decimal("140.00"), 'activity_type': u'ip'}, 
     {'cost__sum': Decimal("100.00"), 'activity_type': u'op'}, 
     {'cost__sum': Decimal("0.00"), 'activity_type': u'ip'}]

In the result set there are 2 'ip' type encounters. This is because it is not grouped by only activity_type but by activity_type AND cost which does not give the intended result. The generated SQL query for this is:

在结果集中有2个'ip'类型遇到。这是因为它不是仅按activity_type分组,而是按活动类型和成本分组,而不是给出预期结果。生成的SQL查询是:

SELECT "encounter_encounter"."activity_type", 
    SUM("encounter_encounter"."total_cost") AS "total_cost__sum" 
    FROM "encounter_encounter" 
    GROUP BY "encounter_encounter"."activity_type", 
             "encounter_encounter"."total_cost"        <<<< THIS MESSES THINGS
    ORDER BY "encounter_encounter"."total_cost" DESC

How can I make this query work as expected (and as implied by the docs if I am not getting it wrong) and make it only do a group by on activity_type?

如何让这个查询按预期工作(如果我没有弄错的话,文档所暗示的那样)并使它只在activity_type上执行一个组?

1 个解决方案

#1


11  

As @Skirmantas correctly pointed, the problem was related to order_by. Although it is not explicitly stated in the query, the default ordering in the model's Meta class is added to the query, which is then added to the group by clause because SQL requires so.

正如@Skirmantas正确指出的那样,问题与order_by有关。虽然在查询中没有明确说明,但是模型的Meta类中的默认排序被添加到查询中,然后将其添加到group by子句中,因为SQL需要这样。

The solution is either to remove the default ordering or add an empty order_by() to reset ordering:

解决方案是删除默认排序或添加空order_by()以重置排序:

>>> Encounter.objects.values('activity_type').annotate(Sum('cost')).order_by()

#1


11  

As @Skirmantas correctly pointed, the problem was related to order_by. Although it is not explicitly stated in the query, the default ordering in the model's Meta class is added to the query, which is then added to the group by clause because SQL requires so.

正如@Skirmantas正确指出的那样,问题与order_by有关。虽然在查询中没有明确说明,但是模型的Meta类中的默认排序被添加到查询中,然后将其添加到group by子句中,因为SQL需要这样。

The solution is either to remove the default ordering or add an empty order_by() to reset ordering:

解决方案是删除默认排序或添加空order_by()以重置排序:

>>> Encounter.objects.values('activity_type').annotate(Sum('cost')).order_by()