Django फ़िल्टर बनाम एकल वस्तु के लिए मिलता है?


147

मैं कुछ सहयोगियों के साथ इस पर बहस कर रहा था। क्या Django में एक वस्तु को पुनः प्राप्त करने का एक पसंदीदा तरीका है जब आप केवल एक की उम्मीद कर रहे हैं?

दो स्पष्ट तरीके हैं:

try:
    obj = MyModel.objects.get(id=1)
except MyModel.DoesNotExist:
    # We have no object! Do something...
    pass

तथा:

objs = MyModel.objects.filter(id=1)

if len(objs) == 1:
    obj = objs[0]
else:
    # We have no object! Do something...
    pass

पहली विधि व्यवहारिक रूप से अधिक सही लगती है, लेकिन नियंत्रण प्रवाह में अपवादों का उपयोग करती है जो कुछ ओवरहेड का परिचय दे सकती हैं। दूसरा अधिक गोल चक्कर है, लेकिन कभी भी अपवाद नहीं उठाया जाएगा।

इनमें से कौन सा विचार बेहतर है? कौन सा अधिक कुशल है?

जवाबों:


177

get()इस मामले के लिए विशेष रूप से प्रदान की जाती है । इसका इस्तेमाल करें।

विकल्प 2 लगभग ठीक है कि कैसे get()विधि वास्तव में Django में लागू की जाती है, इसलिए कोई "प्रदर्शन" अंतर नहीं होना चाहिए (और जिस तथ्य के बारे में आप सोच रहे हैं वह इंगित करता है कि आप प्रोग्रामिंग के कार्डिनल नियमों में से एक का उल्लंघन कर रहे हैं, अर्थात कोशिश कर रहे हैं। कोड को ऑप्टिमाइज़ करने से पहले इसे लिखा और प्रोफाइल भी किया गया है - जब तक कि आपके पास कोड नहीं है और इसे चला सकते हैं, आप नहीं जानते कि यह कैसा प्रदर्शन करेगा, और इससे पहले ऑप्टिमाइज़ करने की कोशिश करना दर्द का एक रास्ता है)।


सब कुछ सही है लेकिन उत्तर देने के लिए शायद अधिक जानकारी जोड़ी जानी चाहिए? 1. पायथन प्रयास (/ EAFP देखें ) को छोड़कर प्रोत्साहित करता है , यही कारण QS.get()है कि अच्छा है। 2. विवरण मामला: क्या "केवल एक ही उम्मीद करना" का अर्थ है हमेशा 0-1 ऑब्जेक्ट्स, या 2+ ऑब्जेक्ट्स होना संभव है और उस मामले को भी संभाला जाना चाहिए (इस मामले len(objs)में एक भयानक विचार है)? 3. एक बेंचमार्क के बिना ओवरहेड के बारे में कुछ भी न try/except
मानें

> कोड को अनुकूलित करने की कोशिश करने से पहले इसे लिखा और प्रोफाइल किया जा चुका है। यह एक दिलचस्प टिप्पणी है। मैंने हमेशा सोचा कि मुझे इसे लागू करने से पहले किसी चीज़ को लागू करने का सबसे वैकल्पिक तरीका सोचना चाहिए। क्या वह गलत है? क्या आप इस बिंदु पर विस्तार से बता सकते हैं? क्या कुछ संसाधन हैं जो इस बारे में विस्तार से बताते हैं?
पार्थ शर्मा

मुझे आश्चर्य है कि किसी ने भी पहले उल्लेख नहीं किया है ()। अन्य सलाह यह इंगित करती है कि यह इस परिदृश्य के लिए की गई कॉल है। stackoverflow.com/questions/5123839/…
NeilG

29

आप django- कष्टप्रद नामक एक मॉड्यूल स्थापित कर सकते हैं और फिर ऐसा कर सकते हैं:

from annoying.functions import get_object_or_None

obj = get_object_or_None(MyModel, id=1)

if not obj:
    #omg the object was not found do some error stuff

1
ऐसा तरीका होना कष्टप्रद क्यों है? मुझे ठीक लग रहा है!
थॉमस

17

1 सही है। पायथन में एक अपवाद एक वापसी के बराबर ओवरहेड है। एक सरल सबूत के लिए आप देख सकते हैं इस

2 यह वही है जो Django बैकएंड में कर रहा है। यदि कोई वस्तु नहीं मिलती है या एक से अधिक वस्तु मिलती है तो getकॉल filterऔर एक अपवाद को बढ़ाता है।


1
यह परीक्षा काफी अनुचित है। एक अपवाद को फेंकने में ओवरहेड का एक बड़ा हिस्सा स्टैक ट्रेस का हैंडलिंग है। उस परीक्षण में एक स्टैक की लंबाई 1 थी जो कि आप आमतौर पर किसी एप्लिकेशन में पाएंगे।
रॉब यंग

@ रब यंग: तुम्हारा क्या मतलब है? आपको स्टैक ट्रेस हैंडलिंग में कहाँ दिखाई देता है "अनुमति के बजाय माफी माँगें" योजना? प्रसंस्करण समय अपवाद की यात्रा की दूरी पर निर्भर करता है, न कि यह सब कितना गहरा होता है (जब हम जावा में नहीं लिख रहे होते हैं और e.printStackTrace ()) कहते हैं। और सबसे अधिक बार (जैसे शब्दकोश देखने में) - अपवाद केवल नीचे फेंक दिया गया है try
टॉमस गैंडर

12

मैं पार्टी में थोड़ा लेट हो गया हूं, लेकिन Django 1.6 के साथ first()क्वेरीसेट पर विधि है।

https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.first


क्वेरी से मेल खाता पहला ऑब्जेक्ट लौटाता है, या कोई भी नहीं अगर कोई मिलान ऑब्जेक्ट नहीं है। यदि क्वेरीसेट में कोई क्रम निर्धारित नहीं है, तो क्वेरीसेट स्वचालित रूप से प्राथमिक कुंजी द्वारा आदेशित होता है।

उदाहरण:

p = Article.objects.order_by('title', 'pub_date').first()
Note that first() is a convenience method, the following code sample is equivalent to the above example:

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None

यह गारंटी नहीं है कि आपके पास क्वेरी में केवल एक ही वस्तु है
py_dude

8

मैं Django के किसी भी अनुभव के साथ बात नहीं कर सकता, लेकिन विकल्प # 1 स्पष्ट रूप से उस प्रणाली को बताता है जो आप 1 ऑब्जेक्ट के लिए पूछ रहे हैं, जबकि दूसरा विकल्प नहीं है। इसका मतलब यह है कि विकल्प # 1 अधिक आसानी से कैश या डेटाबेस इंडेक्स का लाभ ले सकता है, खासकर जहां आप जिस विशेषता को फ़िल्टर कर रहे हैं वह अद्वितीय होने की गारंटी नहीं है।

इसके अलावा (फिर से, अटकलें) दूसरा विकल्प कुछ प्रकार के परिणाम संग्रह या पुनरावृत्त वस्तु बनाना हो सकता है क्योंकि फ़िल्टर () कॉल सामान्य रूप से कई पंक्तियों को वापस कर सकता है। आप इसे प्राप्त () के साथ बायपास करेंगे।

अंत में, पहला विकल्प छोटा है और अतिरिक्त अस्थायी चर को छोड़ देता है - केवल एक मामूली अंतर लेकिन हर छोटी मदद।


Django के साथ कोई अनुभव नहीं है लेकिन अभी भी मौके पर है। स्पष्ट रूप से, स्पष्ट और सुरक्षित होने के नाते, अच्छे सिद्धांत भाषा या रूपरेखा नहीं हैं।
नेवलिस

8

वह सब काम क्यों करते हैं? 1 बेसिन शॉर्टकट के साथ 4 लाइनों को बदलें। (यह अपनी कोशिश करता है / को छोड़कर)

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, id=1)

1
जब यह वांछित व्यवहार होता है तो यह बहुत अच्छा है, लेकिन कभी-कभी, आप लापता वस्तु बनाना चाहते हैं, या पुल वैकल्पिक जानकारी थी।
सिंगलएनजेशन इलिमिनेशन

2
इसके लिए क्या Model.objects.get_or_create()है
बोटकॉडर

7

अपवादों के बारे में कुछ और जानकारी। अगर उन्हें नहीं उठाया जाता है, तो वे लगभग कुछ भी नहीं खर्च करते हैं। इस प्रकार यदि आप जानते हैं कि आप शायद एक परिणाम के लिए जा रहे हैं, तो अपवाद का उपयोग करें, क्योंकि सशर्त अभिव्यक्ति का उपयोग करके आप हर बार जाँच की लागत का भुगतान करते हैं, चाहे जो भी हो। दूसरी ओर, वे एक सशर्त अभिव्यक्ति की तुलना में थोड़ा अधिक खर्च करते हैं जब वे उठाए जाते हैं, इसलिए यदि आप कुछ आवृत्ति के साथ परिणाम नहीं होने की उम्मीद करते हैं (कहते हैं, समय का 30%, यदि स्मृति कार्य करता है), तो सशर्त जांच निकल जाती है थोड़ा सस्ता होना।

लेकिन यह Django का ORM है, और संभवतः डेटाबेस के लिए गोल-यात्रा, या यहां तक ​​कि एक कैश्ड परिणाम, प्रदर्शन विशेषताओं पर हावी होने की संभावना है, इसलिए पठनीयता का पक्ष लें, इस मामले में, चूंकि आप बिल्कुल एक परिणाम की उम्मीद करते हैं, उपयोग करें get()


4

मैंने इस समस्या के साथ थोड़ा खेला है और पता चला है कि विकल्प 2 दो SQL प्रश्नों को निष्पादित करता है, जो कि इस तरह के एक सरल कार्य के लिए अत्यधिक है। मेरा एनोटेशन देखें:

objs = MyModel.objects.filter(id=1) # This does not execute any SQL
if len(objs) == 1: # This executes SELECT COUNT(*) FROM XXX WHERE filter
    obj = objs[0]  # This executes SELECT x, y, z, .. FROM XXX WHERE filter
else: 
    # we have no object!  do something
    pass

किसी एकल क्वेरी को निष्पादित करने वाला एक समतुल्य संस्करण है:

items = [item for item in MyModel.objects.filter(id=1)] # executes SELECT x, y, z FROM XXX WHERE filter
count = len(items) # Does not execute any query, items is a standard list.
if count == 0:
   return None
return items[0]

इस दृष्टिकोण पर स्विच करके, मैं अपने प्रश्नों के निष्पादन की संख्या को काफी हद तक कम करने में सक्षम था।


1

दिलचस्प सवाल है, लेकिन मेरे लिए समय से पहले अनुकूलन के # 2 विकल्प विकल्प। मुझे यकीन नहीं है कि कौन अधिक परफ़ॉर्मेंट है, लेकिन विकल्प # 1 निश्चित रूप से मेरे लिए अधिक आकर्षक और आकर्षक लगता है।


1

मैं एक अलग डिजाइन का सुझाव देता हूं।

यदि आप किसी संभावित परिणाम पर कोई कार्य करना चाहते हैं, तो आप QuerySet से प्राप्त कर सकते हैं, जैसे: http://djangosnippets.org/snippets/734/

परिणाम बहुत बढ़िया है, आप उदाहरण के लिए कर सकते हैं:

MyModel.objects.filter(id=1).yourFunction()

यहां, फ़िल्टर एक खाली क्वेरी या एकल आइटम के साथ एक क्वेरीसेट देता है। आपके कस्टम क्वेरी कार्य भी श्रृंखला योग्य और पुन: प्रयोज्य हैं। यदि आप इसे अपनी सभी प्रविष्टियों के लिए करना चाहते हैं:MyModel.objects.all().yourFunction() :।

वे व्यवस्थापक इंटरफ़ेस में कार्रवाई के रूप में उपयोग किए जाने के लिए भी आदर्श हैं:

def yourAction(self, request, queryset):
    queryset.yourFunction()

0

विकल्प 1 अधिक सुरुचिपूर्ण है, लेकिन कोशिश का उपयोग करना सुनिश्चित करें।

अपने स्वयं के अनुभव से मैं आपको बता सकता हूं कि कभी-कभी आपको यकीन है कि डेटाबेस में संभवतः एक से अधिक मिलान वाली वस्तु नहीं हो सकती है, और फिर भी दो होंगे ... (इसके प्राथमिक कुंजी द्वारा ऑब्जेक्ट प्राप्त करते समय) को छोड़कर।


0

इस मुद्दे पर एक और जोड़ने के लिए क्षमा करें, लेकिन मैं django पेजिनेटर का उपयोग कर रहा हूं, और मेरे डेटा व्यवस्थापक ऐप में, उपयोगकर्ता को क्वेरी करने के लिए क्या लेने की अनुमति है। कभी-कभी यह एक दस्तावेज़ की आईडी होती है, लेकिन अन्यथा यह एक सामान्य क्वेरी है जो एक से अधिक ऑब्जेक्ट, यानी, एक क्वेरी से लौटती है।

यदि उपयोगकर्ता आईडी पर सवाल उठाता है, तो मैं चला सकता हूं:

Record.objects.get(pk=id)

जो django के पेजिनेटर में एक त्रुटि फेंकता है, क्योंकि यह एक Record है ना कि Queryset of Records।

मुझे चलाने की आवश्यकता है:

Record.objects.filter(pk=id)

जो इसमें एक आइटम के साथ एक क्वेरी को लौटाता है। फिर पेजिनेटर ठीक काम करता है।


पेजिनेटर का उपयोग करने के लिए - या किसी भी कार्यक्षमता जो किसी क्वेरीस की अपेक्षा करती है - आपकी क्वेरी को क्वेरीसेट वापस करना होगा। .Filter () और .get (), .filter () के साथ छड़ी और "pk = id" फिल्टर की आपूर्ति करने के बीच स्विच न करें, जैसा कि आप पहले ही महसूस कर चुके हैं। यह इस उपयोग के मामले के लिए पैटर्न है।
कॉर्नेल मैसन

0

।प्राप्त()

दिए गए लुकअप पैरामीटर्स से मेल खाती हुई वस्तु, जो फील्ड लुकअप में वर्णित प्रारूप में होनी चाहिए।

get () एक से अधिक ऑब्जेक्ट पाए जाने पर MultipleObjectsReturned उठाता है। MultipleObjectsReturned अपवाद मॉडल वर्ग का एक गुण है।

यदि कोई ऑब्जेक्ट दिए गए मापदंडों के लिए नहीं मिला, तो DoNotExist अपवाद प्राप्त करें () उठाएं। यह अपवाद भी मॉडल वर्ग का एक गुण है।

.filter ()

दिए गए लुकअप मापदंडों से मेल खाने वाली वस्तुओं से युक्त एक नया क्वेरीसेट लौटाता है।

ध्यान दें

जब आप एक ही अनोखी वस्तु प्राप्त करना चाहते हैं, तो get () का उपयोग करें और जब आप अपने लुकअप मापदंडों से मेल खाने वाली सभी वस्तुओं को प्राप्त करना चाहते हैं तो फ़िल्टर () करें।

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