Django गिनती और समूह के लिए बराबर है


91

मेरे पास एक मॉडल है जो इस तरह दिखता है:

class Category(models.Model):
    name = models.CharField(max_length=60)

class Item(models.Model):
    name = models.CharField(max_length=60)
    category = models.ForeignKey(Category)

मैं प्रत्येक श्रेणी के लिए आइटमों की गिनती (बस गिनती) का चयन करना चाहता हूं, इसलिए SQL में यह इस तरह सरल होगा:

select category_id, count(id) from item group by category_id

वहाँ यह "Django रास्ता" करने के बराबर है? या सादा SQL एकमात्र विकल्प है? मैं Django में गिनती () विधि से परिचित हूं , हालांकि मैं यह नहीं देखता कि समूह कैसे वहां फिट होगा।



@CiroSantilli 巴拿馬 文件 ill ill is यह एक डुप्लिकेट कैसे है? यह प्रश्न 2008 में पूछा गया था, और आप जिसका उल्लेख कर रहे हैं वह 2 साल बाद है।
सेर्गेई गोलोवचेंको

वर्तमान सर्वसम्मति को "गुणवत्ता" द्वारा बंद करना है: < meta.stackexchange.com/questions/147643/… > चूंकि "गुणवत्ता" औसत दर्जे का नहीं है, मैं सिर्फ upvotes द्वारा जाता हूं। ;-) संभवतः यह नीचे आता है कि किस प्रश्न ने शीर्षक पर सर्वश्रेष्ठ नौसिखिया Google कीवर्ड मारा।
सिरो सेंटिल्ली 郝海东 i iro i 法轮功

जवाबों:


131

यहाँ, जैसा कि मैंने अभी-अभी खोजा है, यह Django 1.1 एकत्रीकरण एपीआई के साथ कैसे करना है:

from django.db.models import Count
theanswer = Item.objects.values('category').annotate(Count('category'))

3
Django में अधिकांश चीजें पसंद हैं, इनमें से कोई भी देखने के लिए समझ में नहीं आता है (लेकिन Django में अधिकांश चीजों के विपरीत) एक बार जब मैंने वास्तव में कोशिश की, तो यह बहुत बढ़िया था: P
jsh

3
ध्यान दें कि आप उपयोग करने की आवश्यकता order_by()है, तो 'category'डिफ़ॉल्ट अनुक्रम नहीं है। (डैनियल का अधिक व्यापक उत्तर देखें।)
रिक वेस्टेरा

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

58

( अपडेट : पूर्ण ओआरएम एकत्रीकरण समर्थन अब Django 1.1 में शामिल है । निजी APIs का उपयोग करने के बारे में नीचे दी गई चेतावनी के लिए सही है। यहाँ प्रलेखित विधि अब Django के 1.1 संस्करण के बाद के संस्करणों में काम नहीं करती है। मैंने यह पता लगाने के लिए खोदा नहीं है; यदि आप 1.1 पर हैं या बाद में आपको वास्तविक एकत्रीकरण एपीआई का उपयोग करना चाहिए ।)

कोर एकत्रीकरण समर्थन पहले से ही 1.0 में था; यह अभी तक अविभाजित, असमर्थित है, और इसके ऊपर अभी तक एक अनुकूल एपीआई नहीं है। लेकिन यहाँ है कि आप इसे 1.1 आने तक वैसे भी उपयोग कर सकते हैं (अपने जोखिम पर, और पूरी जानकारी में कि query.group_by विशेषता सार्वजनिक API का हिस्सा नहीं है और बदल सकती है):

query_set = Item.objects.extra(select={'count': 'count(1)'}, 
                               order_by=['-count']).values('count', 'category')
query_set.query.group_by = ['category_id']

यदि आप फिर क्वेरी_सेट पर पुनरावृति करते हैं, तो प्रत्येक लौटाया गया मान "श्रेणी" कुंजी और "गणना" कुंजी के साथ एक शब्दकोश होगा।

आपको यहां ऑर्डर करने की आवश्यकता नहीं है, यह सिर्फ यह प्रदर्शित करने के लिए शामिल है कि यह कैसे किया जाता है (इसे .xtra () कॉल में किया जाना चाहिए, क्वेरी कंस्ट्रक्शन चेन में कहीं और नहीं)। इसके अलावा, आप गिनती (1) के बजाय सिर्फ काउंट (आईडी) कह सकते हैं, लेकिन बाद वाला अधिक कुशल हो सकता है।

यह भी ध्यान दें कि जब .query.group_by को सेट किया जाता है, तो मान वास्तविक DB स्तंभ नाम ('श्रेणी_आईडी') होना चाहिए न कि Django फ़ील्ड नाम ('श्रेणी')। इसका कारण यह है कि आप क्वेरी इंटर्नल्स को ऐसे स्तर पर ट्विक कर रहे हैं जहां सब कुछ DB शब्दों में है, न कि Django के शब्दों में।


पुरानी विधि के लिए +1। यहां तक ​​कि अगर वर्तमान में असमर्थित है, तो यह कम से कम कहने के लिए ज्ञानवर्धक है। कमाल है, सच में।
हवाई

Docs.djangoproject.com/en/dev/topics/db/aggregation/… पर Django एकत्रीकरण एपीआई पर एक नज़र डालें। इसके साथ अन्य जटिल कार्य किए जा सकते हैं, वहाँ आपको कुछ शक्तिशाली उदाहरण मिलेंगे।
सेफर 2

@ serfer2 हाँ, वे डॉक्स पहले से ही इस उत्तर के ऊपर से जुड़े हुए हैं।
कार्ल मेयर

56

चूँकि मैं थोड़ा उलझन में था कि कैसे Django 1.1 में समूहीकरण किया गया था। मुझे लगा कि मैं यहाँ पर विस्तार से बताऊंगा कि आप इसका उपयोग कैसे करते हैं। माइकल ने जो कहा, उसे दोहराने के लिए सबसे पहले:

यहाँ, जैसा कि मैंने अभी-अभी खोजा है, यह Django 1.1 एकत्रीकरण एपीआई के साथ कैसे करना है:

from django.db.models import Count
theanswer = Item.objects.values('category').annotate(Count('category'))

ध्यान दें कि आपको इसकी आवश्यकता है from django.db.models import Count!

यह केवल श्रेणियों का चयन करेगा और फिर एक एनोटेशन नाम जोड़ेगा category__count। डिफ़ॉल्ट ऑर्डर के आधार पर यह आपके लिए आवश्यक हो सकता है, लेकिन यदि डिफ़ॉल्ट ऑर्डर इसके अलावा categoryकिसी अन्य फ़ील्ड का उपयोग करता है तो यह काम नहीं करेगा । इसका कारण यह है कि ऑर्डर करने के लिए आवश्यक फ़ील्ड भी चुने गए हैं और प्रत्येक पंक्ति को अद्वितीय बनाते हैं, इसलिए आपको ऐसा सामान नहीं मिलेगा जो आप चाहते हैं। इसे ठीक करने का एक त्वरित तरीका आदेश को रीसेट करना है:

Item.objects.values('category').annotate(Count('category')).order_by()

यह ठीक वैसा ही परिणाम उत्पन्न करना चाहिए जैसा आप चाहते हैं। एनोटेशन का नाम सेट करने के लिए आप इसका उपयोग कर सकते हैं:

...annotate(mycount = Count('category'))...

तब आपके पास mycountपरिणामों में एक एनोटेशन होगा ।

ग्रुपिंग के बारे में बाकी सब कुछ मेरे लिए बहुत सीधा था। अधिक विस्तृत जानकारी के लिए Django एकत्रीकरण एपीआई की जाँच करना सुनिश्चित करें ।


1
। कार्रवाई के एक ही सेट ( 'category__category') विदेशी कुंजी क्षेत्र Item.objects.values पर प्रदर्शन करने के लिए व्याख्या (गणना ( 'category__category')) order_by ()।
उत्परिवर्ती

डिफ़ॉल्ट ऑर्डरिंग फ़ील्ड क्या है यह कैसे निर्धारित किया जाता है?
बोगाटियर

2

यह कैसा है? (धीमी गति से अन्य।)

counts= [ (c, Item.filter( category=c.id ).count()) for c in Category.objects.all() ]

यह छोटा होने का लाभ है, भले ही यह बहुत पंक्तियों को प्राप्त करता हो।


संपादित करें।

एक क्वेरी संस्करण। BTW, यह अक्सर डेटाबेस में SELECT COUNT (*) से अधिक तेज़ होता है। यह देखने की कोशिश करो।

counts = defaultdict(int)
for i in Item.objects.all():
    counts[i.category] += 1

यह अच्छा और छोटा है, हालांकि मैं प्रत्येक श्रेणी के लिए एक अलग डेटाबेस कॉल करने से बचना चाहूंगा।
सर्गेई गोलोवचेंको

यह सरल मामलों के लिए वास्तव में अच्छा दृष्टिकोण है। यह तब होता है जब आपके पास एक बड़ा डेटासेट होता है, और आप एक गिनती के अनुसार + लिमिट (यानी पेजेट) ऑर्डर करना चाहते हैं, बिना टन डेटा के नीचे खींचे बिना।
कार्ल मेयर

@ कार्ल मेयर: सच - यह एक बड़े डेटासेट के लिए कुत्ते का बच्चा हो सकता है; हालाँकि, आपको इसके बारे में सुनिश्चित करने के लिए बेंचमार्क करने की आवश्यकता है। इसके अलावा, यह असमर्थित सामान पर भी निर्भर नहीं करता है; यह तब तक अंतरिम में काम करता है जब तक कि असमर्थित सुविधाओं का समर्थन नहीं किया जाता है।
एस.लॉट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.