Django में SELECT COUNT (*) GROUP BY और ORDER BY कैसे करें?


99

मैं सिस्टम के माध्यम से होने वाली सभी घटनाओं पर नज़र रखने के लिए एक लेनदेन मॉडल का उपयोग कर रहा हूं

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() 
    ......

मैं अपने सिस्टम में शीर्ष 5 अभिनेताओं को कैसे प्राप्त करूं?

Sql में यह मूल रूप से होगा

SELECT actor, COUNT(*) as total 
FROM Transaction 
GROUP BY actor 
ORDER BY total DESC

जवाबों:


181

प्रलेखन के अनुसार, आपको उपयोग करना चाहिए:

from django.db.models import Count
Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')

मान (): निर्दिष्ट करता है कि कौन से कॉलम "समूह द्वारा" उपयोग किए जाने वाले हैं

Django डॉक्स:

"जब एक मान () क्लॉज़ का उपयोग परिणाम सेट में दिए गए कॉलम को बाधित करने के लिए किया जाता है, तो एनोटेशन का मूल्यांकन करने का तरीका थोड़ा अलग होता है। मूल क्वेरी में प्रत्येक परिणाम के लिए एनोटेट परिणाम को वापस करने के बजाय, मूल परिणाम के अनुसार समूहीकृत किया जाता है। मूल्यों () खंड में निर्दिष्ट क्षेत्रों के अनूठे संयोजन के लिए "

एनोटेट (): समूहीकृत मूल्यों पर एक ऑपरेशन निर्दिष्ट करता है

Django डॉक्स:

सारांश मूल्यों को उत्पन्न करने का दूसरा तरीका एक क्वेरीसेट में प्रत्येक वस्तु के लिए एक स्वतंत्र सारांश उत्पन्न करना है। उदाहरण के लिए, यदि आप पुस्तकों की सूची प्राप्त कर रहे हैं, तो आप जानना चाह सकते हैं कि प्रत्येक पुस्तक में कितने लेखकों का योगदान है। प्रत्येक पुस्तक के लेखक के साथ कई-कई संबंध हैं; हम क्वेरीसैट में प्रत्येक पुस्तक के लिए इस रिश्ते को संक्षेप में प्रस्तुत करना चाहते हैं।

एनोटेट () क्लॉज का उपयोग करके प्रति-वस्तु सारांश उत्पन्न किया जा सकता है। जब एक एनोटेट () क्लॉज निर्दिष्ट किया जाता है, तो क्वेरीसैट में प्रत्येक ऑब्जेक्ट को निर्दिष्ट मानों के साथ एनोटेट किया जाएगा।

खण्ड द्वारा आदेश आत्म व्याख्यात्मक है।

संक्षेप में: आप समूह बनाते हैं, लेखकों की क्वेरी बनाते हुए, एनोटेशन जोड़ते हैं (यह दिए गए मानों में एक अतिरिक्त फ़ील्ड जोड़ देगा) और अंत में, आप उन्हें इस मान से ऑर्डर करते हैं

अधिक जानकारी के लिए https://docs.djangoproject.com/en/dev/topics/db/aggregation/ देखें

नोट करने के लिए अच्छा है: यदि गणना का उपयोग करते हैं, तो गणना के लिए पारित मूल्य एकत्रीकरण को प्रभावित नहीं करता है, बस अंतिम मूल्य को दिया गया नाम है। मूल्यों के अनूठे संयोजनों द्वारा एग्रीगेटर समूह (जैसा कि ऊपर उल्लेख किया गया है), गणना द्वारा पारित मूल्य से नहीं। निम्नलिखित प्रश्न समान हैं:

Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total')
Transaction.objects.all().values('actor').annotate(total=Count('id')).order_by('total')

मेरे लिए यह काम किया है Transaction.objects.all().values('actor').annotate(total=Count('actor')).order_by('total'), django.db.models से गिनती आयात करना मत भूलना। धन्यवाद
इवानो

3
नोट करने के लिए अच्छा है: अगर Count(और शायद अन्य एग्रीगेटर्स) का उपयोग कर रहे हैं , तो मूल्य एकत्रीकरण को Countप्रभावित नहीं करता है, बस अंतिम मूल्य को नाम दिया गया है। के अद्वितीय संयोजनों द्वारा एग्रीगेटर समूह values(जैसा कि ऊपर उल्लेख किया गया है), पास किए गए मूल्य से नहीं Count
क्रोनोसैपिएंस

तुम भी faceting प्राप्त करने के लिए खोज परिणाम क्वेरी सेट पोस्टग्रेज के लिए इसका इस्तेमाल कर सकते हैं!
येकाटा

2
@kronosapiens यह इसे प्रभावित करता है, आजकल कम से कम (मैं Django 2.1.4 का उपयोग कर रहा हूं)। उदाहरण में, totalदिया गया नाम और sql में प्रयुक्त गणना है, COUNT('actor')जो इस मामले में कोई फर्क नहीं पड़ता, लेकिन अगर उदाहरण के लिए values('x', 'y').annotate(count=Count('x')), आपको मिलेगा COUNT(x), COUNT(*)या नहीं COUNT(x, y), तो बस इसे ./manage.py shell
आज़माया

35

जैसे @Alvaro ने GROUP BYबयान के लिए Django के प्रत्यक्ष समकक्ष का जवाब दिया है:

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']

तब ऐसे दृष्टिकोण WOULDN'T काम करते हैं:

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 () के साथ सहभागिता


3
.order_by()orderingमेटा में मुझे बचाया ।
बब्केन वर्दयान 11
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.