Seperti @Alvaro telah menjawab padanan langsung Django untuk GROUP BY
pernyataan:
SELECT actor, COUNT(*) AS total
FROM Transaction
GROUP BY actor
adalah melalui penggunaan values()
dan annotate()
metode sebagai berikut:
Transaction.objects.values('actor').annotate(total=Count('actor')).order_by()
Namun satu hal lagi yang harus diperhatikan:
Jika model memiliki pengurutan default yang ditentukan class Meta
, .order_by()
klausul wajib untuk hasil yang sesuai. Anda tidak bisa melewatkannya bahkan ketika tidak ada tujuan pemesanan.
Selanjutnya, untuk kode kualitas tinggi, disarankan untuk selalu meletakkan .order_by()
klausul setelahnya annotate()
, bahkan jika tidak ada class Meta: ordering
. Pendekatan seperti itu akan membuat pernyataan tahan di masa depan: itu akan berfungsi seperti yang dimaksudkan, terlepas dari perubahan apa pun di masa mendatang class Meta: ordering
.
Izinkan saya memberi Anda sebuah contoh. Jika model memiliki:
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']
Maka pendekatan seperti itu TIDAK AKAN berhasil:
Transaction.objects.values('actor').annotate(total=Count('actor'))
Itu karena Django melakukan tambahan GROUP BY
pada setiap bidang diclass Meta: ordering
Jika Anda ingin mencetak kueri:
>>> print Transaction.objects.values(
SELECT "Transaction"."actor_id", COUNT("Transaction"."actor_id") AS "total"
FROM "Transaction"
GROUP BY "Transaction"."actor_id", "Transaction"."id"
Akan jelas bahwa agregasi TIDAK akan berfungsi sebagaimana mestinya dan oleh karena itu .order_by()
klausul harus digunakan untuk menghapus perilaku ini dan mendapatkan hasil agregasi yang sesuai.
Lihat: Interaksi dengan pengurutan default atau order_by () dalam dokumentasi resmi Django.