2012-04-19 18 views
7

मेरे पास एक मॉडल XYZ है और मुझे किसी दिए गए क्वेरीसेट के लिए फ़ील्ड ए, बी, और अभिव्यक्ति x/y के लिए अधिकतम मान प्राप्त करने की आवश्यकता है।Django अभिव्यक्तियों के साथ कुल प्रश्न

यह फ़ील्ड के लिए खूबसूरती से काम करता है। कुछ ऐसा:

>>> XYZ.all().aggregate(Max('a')) 

... {'a__max': 10} 

हालांकि, मुझे अभिव्यक्तियों के लिए ऐसा करने का कोई तरीका नहीं मिल रहा है। की तरह कुछ कोशिश कर रहा है: त्रुटि देता

>>> XYZ.all().aggregate(Max(F('x')/F('y'))) 

:

*** AttributeError: 'ExpressionNode' object has no attribute 'split' 

और की तरह कुछ भी:

*** FieldError: Cannot resolve keyword 'x/y' into field. Choices are: a, b, x, y, id 

कुछ कोशिश कर रहा है की तरह:

>>> XYZ.all().aggregate(Max('x/y')) 

एक त्रुटि देता है

XYZ.all().extra(select={'z':'x/y'}).aggregate(Max('z')) 

भी काम नहीं करता है और इसके बाद के संस्करण के रूप में ही त्रुटि देता है:

FieldError: Cannot resolve keyword 'z' into field. Choices are: a, b, x, y, id 

एक हैक मैं यह कर पाया है:

XYZ.all().extra(select={'z':'MAX(x/y)'})[0].z 

कौन वास्तव में कार्य करता है क्योंकि यह उत्पन्न करता है सही एसक्यूएल, लेकिन यह भ्रमित है क्योंकि मुझे जेड एट्रिब्यूट पर सही मूल्य मिलता है, लेकिन सही उदाहरण नहीं, वह अधिकतम मूल्य वाला है।

बेशक, मैं अतिरिक्त() और order_by() के साथ कच्चे प्रश्न या चाल का भी उपयोग कर सकता हूं, लेकिन यह वास्तव में मुझे समझ में नहीं आता है कि Django एक अच्छी तरह से समग्र प्रश्नों का समर्थन करने के लिए सभी तरह से जाता है, लेकिन अभिव्यक्तियों का समर्थन अपने स्वयं के एफ अभिव्यक्तियों के साथ भी नहीं कर सकता है।

क्या ऐसा करने का कोई तरीका है?

+0

आप जानना चाहते हैं कि क्षमता 'उपयोग करने के लिए एफ दिलचस्पी हो सकती है()' समुच्चय में वस्तुओं [आगामी Django 1.8 रिलीज़ के भाग] (है https://code.djangoproject.com/ wiki/Version1.8Roadmap)। –

उत्तर

6

एसक्यूएल में विभाजित करते हैं, क्या आप चाहते हैं वास्तव में

SELECT x/y, * FROM XYZ ORDER BY x/y DESC LIMIT 1; 
# Or more verbose version of the #1 
SELECT x/y, id, a, b, x, y FROM XYZ GROUP BY x/y, id, a, b, x, y ORDER BY x/y DESC LIMIT 1; 
# Or 
SELECT * FROM XYZ WHERE x/y = (SELECT MAX(x/y) FROM XYZ) LIMIT 1; 

इस प्रकार है Django ORM:

XYZ.objects.extra(select={'z':'x/y'}).order_by('-z')[0] 
# Or 
XYZ.objects.extra(select={'z':'x/y'}).annotate().order_by('-z')[0] 
# Or x/y=z => x=y*z 
XYZ.objects.filter(x=models.F('y') * XYZ.objects.extra(select={'z':'MAX(x/y)'})[0].z)[0] 

संस्करण

XYZ.all().extra(select={'z':'MAX(x/y)'})[0].z 

सही एक्स, वाई और उदाहरण नहीं है क्योंकि MAX समारोह सभी पंक्तियों के बीच में मूल्यांकन किया जाता है, कोई GROUP BY है जब वहाँ दिया है, इसलिए क्वेरीसमूह में सभी उदाहरणों में से एक ही मूल्य है जाएगा zMAX(x/y) के रूप में।

+0

सही है, लेकिन इरादा अधिकतम मूल्य प्राप्त करना है, वापसी के रूप में XYZ.all() से कुल (अधिकतम ('ए')), इसमें शामिल उदाहरण नहीं है। अतिरिक्त चयन वाला संस्करण इसके सबसे नज़दीक है। सही उदाहरण वापस नहीं करना एक भ्रमित दुष्प्रभाव है, लेकिन यह सही मूल्य देता है। जैसा कि मैंने शुरुआती संदेश में कहा था, मैं अतिरिक्त और order_by के समाधानों से अवगत हूं, लेकिन ये स्वीकार्य नहीं हैं क्योंकि उन्हें तालिका के पूर्ण प्रकार की आवश्यकता होती है, न कि एक ही पास। यह Django के लिए एकल फ़ील्ड के साथ अधिकतम समर्थन का समर्थन करने के लिए ज्यादा समझ नहीं आता है लेकिन अभिव्यक्ति नहीं। –

+0

@pjwerneck आपके द्वारा बुलाए जाने वाले भ्रमित दुष्प्रभाव का कारण, मेरे उत्तर के अंतिम अनुच्छेद में वर्णित है। यदि आप केवल अधिकतम मान चाहते हैं, 'XYZ.objects.extra (select = {' z ':' MAX (x/y) '}) [0] .z' पर्याप्त है, कोई ऑर्डर_बी नहीं है। या यहां तक ​​कि सीधे 'कर्सर.एक्सक्यूट (' XYZ से 'MAX (x/y) चुनें)'। मैं आपसे सहमत हूं कि Django कुल डब्ल्यू/अभिव्यक्ति प्रदान नहीं करता है, क्योंकि यह एकल क्षेत्र आईएमओ का समर्थन करने से नाटकीय रूप से अधिक कठिन हो सकता है। – okm

-3

मुझे लगता है कि आप अधिकतम मान अलग

result = XYZ.aggregate(Max('x'), Max('y')) 

मिलना चाहिए और फिर दो क्षेत्रों

result['x__max'] \ result['y__max'] 
+0

यह कोई समझ नहीं आता है। यहां तक ​​कि यदि यह अधिकतम x और y जोड़ी के साथ पंक्ति देता है, तो यह आवश्यक नहीं है कि अधिकतम x/y। उदाहरण के लिए, अधिकतम (x)/अधिकतम (y) पंक्ति 69/16 = 4 है, जबकि अधिकतम (x/y) 8/1 = 8 –

2

आपका उदाहरण जो F() ऑब्जेक्ट्स का उपयोग करता है, Django 1 के बाद ठीक काम करना चाहिए।8:

Book.objects.all().aggregate(price_per_page=Sum(F('price')/F('pages')) 
+0

जानना अच्छा है। धन्यवाद! –

0

1,8 की तुलना में कम संस्करणों के लिए आप इस (गैर-दस्तावेजी) रास्ते में ही प्राप्त कर सकते हैं:

XYZ.all().aggregate(Max(F('x')/F('y'))) 

एक टुकड़ा है कि Django aggregation cheat sheet में Sum() और F() वस्तुओं के साथ एकत्रीकरण को दर्शाता है नहीं है।

Book.objects.all().aggregate(price_per_page=Sum('price_per_page', 
               field='book_price/book_pages')) 

यह पोस्टग्रेज़ के लिए काम करता है, मुझे MySQL के बारे में पता नहीं है।

स्रोत: Django Aggregation: Summation of Multiplication of two fields

संबंधित मुद्दे