Giống như @Alvaro đã trả lời câu lệnh tương đương trực tiếp của Django GROUP BY
:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
là thông qua việc sử dụng values()
và annotate()
các phương pháp như sau:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Tuy nhiên, cần phải chỉ ra một điều nữa:
Nếu mô hình có một thứ tự mặc định được xác định class Meta
, thì .order_by()
mệnh đề này là bắt buộc để có kết quả phù hợp. Bạn chỉ không thể bỏ qua nó ngay cả khi không có ý định đặt hàng.
Hơn nữa, đối với một mã chất lượng cao, bạn nên luôn đặt một .order_by()
mệnh đề sau annotate()
, ngay cả khi không có class Meta: ordering
. Cách tiếp cận như vậy sẽ làm cho tuyên bố có thể chứng minh được trong tương lai: nó sẽ hoạt động đúng như dự kiến, bất kể bất kỳ thay đổi nào trong tương lai class Meta: ordering
.
Hãy để tôi cung cấp cho bạn một ví dụ. Nếu mô hình có:
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']
Sau đó, cách tiếp cận như vậy WOULDN'T hoạt động:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Đó là bởi vì Django thực hiện bổ sung GROUP BY
trên mọi trường trongclass Meta: ordering
Nếu bạn in truy vấn:
>>> 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"
Rõ ràng là tập hợp sẽ KHÔNG hoạt động như dự định và do đó .order_by()
điều khoản phải được sử dụng để xóa hành vi này và nhận được kết quả tổng hợp thích hợp.
Xem: Tương tác với thứ tự mặc định hoặc order_by () trong tài liệu Django chính thức.