เช่นเดียวกับที่ @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 อย่างเป็นทางการ