Так само, як @Alvaro відповів на прямий еквівалент Django GROUP BY
:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
відбувається завдяки використанню values()
та annotate()
методів наступним чином:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Однак слід зазначити ще одне:
Якщо модель має впорядкування за замовчуванням, визначене в class Meta
, .order_by()
пункт є обов'язковим для належних результатів. Ви просто не можете пропустити його, навіть коли жодне замовлення не призначене.
Крім того, для високоякісного коду рекомендується завжди додавати .order_by()
пункт після annotate()
, навіть коли його немає class Meta: ordering
. Такий підхід зробить твердження надійним: він буде працювати так, як передбачалося, незалежно від будь-яких майбутніх змін class Meta: ordering
.
Дозвольте навести вам приклад. Якби модель мала:
class Transaction(models.Model):
actor = models.ForeignKey(User, related_name="actor")
acted = models.ForeignKey(User, related_name="acted", null=True, blank=True)
action_id = models.IntegerField()
class Meta:
ordering = ['id']
Тоді такий підхід БЕЗ РОБОТИ:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Це тому, що Django виконує додаткові дії GROUP BY
на кожному полі вclass Meta: ordering
Якщо ви надрукуєте запит:
>>> print Transaction.objects.values(
SELECT "Transaction"."actor_id", COUNT("Transaction"."actor_id") AS "total"
FROM "Transaction"
GROUP BY "Transaction"."actor_id", "Transaction"."id"
Зрозуміло, що агрегування НЕ працюватиме за призначенням, і тому .order_by()
пункт повинен використовуватися для очищення цієї поведінки та отримання належних результатів агрегування.
Див .: Взаємодія із замовленням за замовчуванням або order_by () в офіційній документації Django.