Точно так же, как @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.