@AlvaroがDjangoの直接の同等のfor GROUP BY
ステートメントに答えたように:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
は次のようにvalues()
とannotate()
メソッドを使用して行われます。
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
ただし、もう1つ指摘する必要があります。
モデルがで定義されたデフォルトの順序を持っている場合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('actor').annotate(total=Count('actor')).query
SELECT "Transaction"."actor_id", COUNT("Transaction"."actor_id") AS "total"
FROM "Transaction"
GROUP BY "Transaction"."actor_id", "Transaction"."id"
集計が意図したとおりに機能しないことは明らかであるため、.order_by()
この動作をクリアして適切な集計結果を得るには、この句を使用する必要があります。
参照:Djangoの公式ドキュメントのデフォルトの順序またはorder_by()との相互作用。