Django: कुछ भी मेल नहीं खाता है, तो एक वस्तु फार्म DB, या 'कोई नहीं' प्राप्त करें


101

क्या कोई Django फ़ंक्शन है जो मुझे ऑब्जेक्ट को डेटाबेस के रूप में प्राप्त करने देगा, या अगर कुछ भी मेल नहीं खाता है?

अभी मैं कुछ का उपयोग कर रहा हूँ जैसे:

foo = Foo.objects.filter(bar=baz)
foo = len(foo) > 0 and foo.get() or None

लेकिन यह बहुत स्पष्ट नहीं है, और यह हर जगह गड़बड़ है।


2
तुम्हें पता है कि तुम सिर्फ फू = फू का उपयोग कर सकते हैं [0] अगर कोई और नहीं है
विजील स्केलेरू

2
पायथन में एक टर्नरी ऑपरेटर है, आपको बूलियन ऑपरेटरों का उपयोग करने की आवश्यकता नहीं है। इसके अलावा, len(foo)बुरा है : " नोट: क्वेरी पर लेन () का उपयोग न करें यदि आप सब करना चाहते हैं तो सेट में रिकॉर्ड की संख्या निर्धारित करें। SQL के SELECT COUNT का उपयोग करके डेटाबेस स्तर पर एक गिनती को संभालना बहुत अधिक कुशल है। (), और Django इस कारण के लिए एक गिनती () विधि प्रदान करता है। " foo = foo[0] if foo.exists() else None
पुन


1
@ mustafa.0x मुझे नहीं लगता कि यहां लागू होता है। यहाँ, गणना के लिए जाँच करने से एक और क्वेरी चलेगी। तब हमें वास्तविक डेटा प्राप्त करने के लिए फिर से क्वेरी करनी होगी। यह एक ऐसा मामला है जहां फ़िल्टर करना और फिर गिनती करना अधिक समझ में आता है ... लेकिन फ़िल्टरिंग और कॉलिंग की तुलना में अधिक समझदारी नहीं first(): P
माइक्रोनएक्सडी

जवाबों:


88

Django 1.6 में आप first()क्वेरीस विधि का उपयोग कर सकते हैं । यह क्वेरी द्वारा मिलान की गई पहली वस्तु है, या यदि कोई मेल खाने वाली वस्तु नहीं है, तो यह वापस आ जाती है।

उपयोग:

p = Article.objects.order_by('title', 'pub_date').first()

19
यह एक अच्छा जवाब नहीं है, अगर कई ऑब्जेक्ट्स मिलते हैं तो MultipleObjectsReturned()उठाया नहीं जाता है, जैसा कि यहां दस्तावेज किया गया है । आप यहाँ
स्लीपाइकल

25
@ स्लीपपीकल मैं असहमत हूं। यह first()ठीक उसी तरह काम करता है जैसे कि यह मान लेता है। यह क्वेरी परिणाम में पहली वस्तु लौटाता है और अगर कई परिणाम मिलते हैं तो परवाह नहीं करता है। यदि आपको कई वस्तुओं की जांच करने की आवश्यकता है, तो आपको .get()इसके बदले उपयोग करना चाहिए ।
सेसर कैनासा

7
[संपादित करें] जैसा कि ओपी ने कहा, .get()उनकी जरूरतों के लिए उपयुक्त नहीं है। इस प्रश्न का सही उत्तर नीचे @kaapstorm द्वारा पाया जा सकता है, और स्पष्ट रूप से अधिक उपयुक्त उत्तर है। filter()इस तरह से दुरुपयोग करने से अप्रत्याशित परिणाम हो सकते हैं, कुछ ऐसा जो ओपी को शायद महसूस नहीं हुआ (जब तक कि मैं यहां कुछ याद नहीं कर रहा हूं)
स्लीपाइकल

1
@sleepycal इस दृष्टिकोण से क्या अनपेक्षित परिणाम उत्पन्न होते हैं?
हॉर्सलओवरफ़ैट

12
यदि आपके डेटाबेस की बाधाएं ऑब्जेक्ट्स में अद्वितीयता का सही प्रबंधन नहीं करती हैं, तो आप किनारे के मामलों को हिट कर सकते हैं, जहां आपके तर्क में केवल एक ऑब्जेक्ट (जो पहले द्वारा चयनित होता है) होने की उम्मीद है, लेकिन वास्तव में कई ऑब्जेक्ट मौजूद हैं। पहले के बजाय प्राप्त () का उपयोग करना आपको बढ़ाकर सुरक्षा की एक अतिरिक्त परत देता है MultipleObjectsReturned()। यदि परिणाम वापस किया जा रहा है, तो कई वस्तुओं को वापस करने की उम्मीद नहीं की जाती है, तो इसे ऐसा नहीं माना जाना चाहिए। यहाँ इस बारे में एक लंबी बहस हुई
स्लीपाइकल

139

इसे करने के दो तरीके हैं;

try:
    foo = Foo.objects.get(bar=baz)
except model.DoesNotExist:
    foo = None

या आप एक आवरण का उपयोग कर सकते हैं:

def get_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

इसे इस तरह बुलाओ

foo = get_or_none(Foo, baz=bar)

8
मुझे यह पसंद नहीं है कि यह कार्यक्षमता के अपवादों का उपयोग कर रहा है - यह अधिकांश भाषाओं में एक बुरा व्यवहार है। अजगर में वह कैसे है?
पीसीवी

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

4
@ पीसीबी: "अधिकांश" भाषाओं के बारे में कोई विश्वसनीय पारंपरिक ज्ञान नहीं है। मुझे लगता है कि आप कुछ विशिष्ट भाषा के बारे में सोचते हैं जो आप उपयोग करते हैं, लेकिन इस तरह के क्वांटिफायर से सावधान रहें। अपवाद धीमी गति से (या उस मामले के लिए "पर्याप्त तेज") हो सकता है, जैसे कि पायथन में कुछ भी। सवाल पर वापस जाना - यह रूपरेखा की कमी है, कि उन्होंने queryset1.6 से पहले ऐसा करने के लिए कोई विधि प्रदान नहीं की ! लेकिन इस निर्माण के लिए - यह सिर्फ अनाड़ी है। यह "बुराई" नहीं है क्योंकि आपकी पसंदीदा भाषा के कुछ ट्यूटोरियल लेखक ने ऐसा कहा। Google का प्रयास करें: "अनुमति के बजाय क्षमा मांगें"।
टॉमस गैंडर

@TomaszGandor: हाँ, यह अनाड़ी और पढ़ने में मुश्किल है, जो भी आपकी पसंदीदा भाषा ट्यूटोरियल कहती है। जब मैं एक अपवाद देखता हूं तो मुझे लगता है कि कुछ गैर-मानक हो रहा है। पठनीयता मायने रखती है। लेकिन मैं मानता हूं कि जब कोई अन्य उचित विकल्प नहीं है, तो आपको इसके लिए जाना चाहिए और कुछ भी बुरा नहीं होगा।
पीसीवी

@ pcv getविधि को वापस नहीं आना चाहिए None, इसलिए एक अपवाद समझ में आता है। आप इसे ऐसे उदाहरणों में उपयोग करने वाले हैं जहाँ आपको यकीन है कि वस्तु वहाँ होगी / वस्तु वहाँ "होना" है। इसके अलावा इस तरह के अपवादों का उपयोग करना 'ठीक' माना जाता है क्योंकि, ठीक है, यह समझ में आता है। आप getएक अलग अनुबंध के साथ चाहते हैं , इसलिए आप अपवाद को पकड़ते हैं और इसे दबा देते हैं, जो कि आप के बाद का बदलाव है।
डैन पासरो

83

सोर्कि के उत्तर में कुछ नमूना कोड जोड़ने के लिए (मैं इसे टिप्पणी के रूप में जोड़ूंगा, लेकिन यह मेरी पहली पोस्ट है, और टिप्पणियों को छोड़ने के लिए मेरे पास पर्याप्त प्रतिष्ठा नहीं है), मैंने एक get_or_none कस्टम प्रबंधक को लागू किया:

from django.db import models

class GetOrNoneManager(models.Manager):
    """Adds get_or_none method to objects
    """
    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except self.model.DoesNotExist:
            return None

class Person(models.Model):
    name = models.CharField(max_length=255)
    objects = GetOrNoneManager()

और अब मैं यह कर सकता हूं:

bob_or_none = Person.objects.get_or_none(name='Bob')

यह बहुत सुरुचिपूर्ण है।
NotSimon

13

आप django कष्टप्रद का उपयोग करने का भी प्रयास कर सकते हैं (इसके अन्य उपयोगी कार्य हैं!)

इसे स्थापित करें:

pip install django-annoying

from annoying.functions import get_object_or_None
get_object_or_None(Foo, bar=baz)

9

फू को इसके कस्टम मैनेजर को दें । यह बहुत आसान है - बस कस्टम मैनेजर में फ़ंक्शन में अपना कोड डालें, कस्टम मैनेजर को अपने मॉडल में सेट करें और इसके साथ कॉल करें Foo.objects.your_new_func(...)

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


4

चाहे वह किसी प्रबंधक या सामान्य फ़ंक्शन के माध्यम से कर रहा हो, आप TRY स्टेटमेंट में 'MultipleObjectsReturned' को भी पकड़ना चाह सकते हैं, क्योंकि यदि आपके kwargs एक से अधिक ऑब्जेक्ट पुनर्प्राप्त करते हैं, तो यह () फ़ंक्शन इसे बढ़ा देगा।

सामान्य कार्य पर निर्माण:

def get_unique_or_none(model, *args, **kwargs):
    try:
        return model.objects.get(*args, **kwargs)
    except (model.DoesNotExist, model.MultipleObjectsReturned), err:
        return None

और प्रबंधक में:

class GetUniqueOrNoneManager(models.Manager):
    """Adds get_unique_or_none method to objects
    """
    def get_unique_or_none(self, *args, **kwargs):
        try:
            return self.get(*args, **kwargs)
        except (self.model.DoesNotExist, self.model.MultipleObjectsReturned), err:
            return None

यह अन्य उत्तरों के सभी सर्वोत्तम बिंदुओं को कैप्चर करता है। एक अच्छा :)
एडवर्ड नेवेल

@ नीरवता, क्या होगा अगर मैं कोई नहीं लौटना चाहता, तो मैं एक चेतावनी संदेश वापस करना चाहता हूं जैसे "कोई मिलान डेटा नहीं" वही एसएएमई पृष्ठ पर प्रदर्शित हो रहा है?
हेलेना

0

यहाँ सहायक फ़ंक्शन पर एक भिन्नता है जो आपको एक QuerySetउदाहरण में वैकल्पिक रूप से पारित करने की अनुमति देता है , यदि आप मॉडल के allऑब्जेक्ट क्वेरीसेट के अलावा एक क्वेरीसेट से अद्वितीय वस्तु (यदि मौजूद है) प्राप्त करना चाहते हैं (जैसे कि बच्चे से संबंधित आइटमों के सबसेट से) मूल उदाहरण):

def get_unique_or_none(model, queryset=None, *args, **kwargs):
    """
        Performs the query on the specified `queryset`
        (defaulting to the `all` queryset of the `model`'s default manager)
        and returns the unique object matching the given
        keyword arguments.  Returns `None` if no match is found.
        Throws a `model.MultipleObjectsReturned` exception
        if more than one match is found.
    """
    if queryset is None:
        queryset = model.objects.all()
    try:
        return queryset.get(*args, **kwargs)
    except model.DoesNotExist:
        return None

यह दो तरह से इस्तेमाल किया जा सकता है, जैसे:

  1. obj = get_unique_or_none(Model, *args, **kwargs) जैसा कि प्रीवियस ने चर्चा की
  2. obj = get_unique_or_none(Model, parent.children, *args, **kwargs)

-1

मुझे लगता है कि ज्यादातर मामलों में आप सिर्फ उपयोग कर सकते हैं:

foo, created = Foo.objects.get_or_create(bar=baz)

केवल अगर यह महत्वपूर्ण नहीं है कि फू तालिका में एक नई प्रविष्टि जोड़ी जाएगी (अन्य कॉलमों में कोई नहीं / डिफ़ॉल्ट मान होंगे)

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