Django annotate и values ​​(): дополнительное поле в 'group by' приводит к неожиданным результатам - PullRequest
3 голосов
/ 11 февраля 2011

Я, должно быть, упускаю что-то очевидное, поскольку поведение не соответствует ожидаемому для этого простого требования. Вот мой класс модели:

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)

Я хочу найти общую стоимость для каждого вида деятельности. Мой запрос:

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

Что дает:

>>> [{'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'}]

В наборе результатов есть 2 встречи типа 'ip'. Это связано с тем, что он не группируется только по activity_type, а по 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

Как я могу заставить этот запрос работать так, как ожидалось (и что подразумевается в документах , если я не ошибаюсь), и заставить его выполнять группирование только по activity_type?

1 Ответ

11 голосов
/ 12 февраля 2011

Как правильно заметил @Skirmantas, проблема была связана с order_by. Хотя это явно не указано в запросе, в запрос добавляется порядок по умолчанию в метаклассе модели, который затем добавляется в предложение group by, поскольку этого требует SQL.

Решением является либо удаление заказа по умолчанию, либо добавление пустого order_by() для сброса заказа:

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