यदि यह मौजूद है, तो मैं इसे कैसे प्राप्त कर सकता हूं या यदि यह मौजूद नहीं है, तो मुझे कैसे मिलेगा?


223

जब मैं मॉडल प्रबंधक से एक वस्तु प्राप्त करने के लिए कहता हूं, तो यह DoesNotExistतब उठता है जब कोई मिलान वस्तु नहीं होती है।

go = Content.objects.get(name="baby")

इसके बजाय DoesNotExist, मैं कैसे हो सकता है goहो सकता है Noneबजाय?

जवाबों:


332

ऐसा करने के लिए कोई 'बिल्ट इन' तरीका नहीं है। Django हर बार DoNotExist अपवाद को बढ़ाएगा। अजगर में इसे संभालने का मुहावरेदार तरीका यह है कि इसे पकड़ने की कोशिश में लपेटें:

try:
    go = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
    go = None

मैंने क्या किया, safe_getमॉडल को उप-वर्ग करना है। मानेगर, ऊपर दिए गए कोड की तरह बनाएं और अपने मॉडल के लिए उस प्रबंधक का उपयोग करें। इस तरह आप लिख सकते हैं: SomeModel.objects.safe_get(foo='bar')


7
अपवाद आयात करने के बजाय SomeModel.DoesNotExist का अच्छा उपयोग।
सुपरमाइच

196
यह हल चार लाइनों का है। मेरे लिए यह बहुत ज्यादा है। Django 1.6 के साथ आप SomeModel.objects.filter(foo='bar').first()इस रिटर्न का पहला मैच, या कोई भी उपयोग कर सकते हैं । यह विफल नहीं होता है अगर वहाँ कई उदाहरण हैंqueryset.get()
guettli

9
मुझे लगता है कि डिफ़ॉल्ट मामलों को संभालने के लिए अपवादों का उपयोग करना बुरी शैली है। हां, "अनुमति के लिए माफी मांगना अधिक आसान है"। लेकिन अपवादों के लिए, मेरी आँखों में अभी भी एक अपवाद का उपयोग किया जाना चाहिए।
कोनस्टेंटिन शुबर्ट 20

8
निहितार्थ की तुलना में स्पष्ट है। जब तक कि प्रदर्शन का कोई कारण नहीं है, filter().first()मुझे लगता है कि अपवाद रास्ता तय करना है।
क्रिश्चियनबॉडी

6
पहला () का उपयोग करना केवल एक अच्छा विचार है यदि आप परवाह नहीं करते हैं जब गुणक होते हैं। अन्यथा, यह समाधान श्रेष्ठ है, क्योंकि यह अभी भी एक अपवाद को फेंक देगा यदि आप अप्रत्याशित रूप से कई वस्तुओं को ढूंढते हैं, जो कि आम तौर पर आप उस मामले में क्या करना चाहते हैं।
रोजडेविद

182

Django 1.6 के बाद से आप पहले () विधि का उपयोग कर सकते हैं :

Content.objects.filter(name="baby").first()

26
इस मामले में, एक से अधिक मिलान होने पर कोई त्रुटि नहीं उठाई जाती है।
कोन्स्टेंटिन शुबर्ट

7
'FeroxTL' आपको इस जवाब के लिए @guettli को श्रेय देने की आवश्यकता है, क्योंकि उन्होंने आपकी पोस्ट से एक साल पहले स्वीकृत उत्तर पर यह टिप्पणी की थी।
colm.anseo

7
@colminator मैं बल्कि कहूंगा कि गुटली को यह सीखना चाहिए कि एक नया उत्तर एक टिप्पणी के रूप में नहीं है यदि वह अपने स्टैकओवरफ़्लो प्रतिष्ठित को उठाना चाहता है :) FeroxTL को एक उत्तर के रूप में एक टिप्पणी के रूप में कुछ और छिपाए जाने के लिए अंक प्राप्त करना चाहिए। आपकी टिप्पणी क्रेडिट के लिए पर्याप्त है, मुझे लगता है कि यदि आपका सुझाव था, तो मुझे जवाब में नहीं जोड़ा जाना चाहिए।
जोकीम

3
@ जोकिम मुझे कोई नया "उत्तर" पोस्ट करने में कोई समस्या नहीं है - सिर्फ क्रेडिट देने के लिए जहां यह देय है :-)
colm.anseo

3
स्वीकृत उत्तर की तुलना में इस दृष्टिकोण के प्रदर्शन के बारे में क्या?
मैक्सकोर

36

Django डॉक्स से

get()DoesNotExistयदि कोई ऑब्जेक्ट दिए गए मापदंडों के लिए नहीं मिला है तो एक अपवाद उठाता है । यह अपवाद भी मॉडल वर्ग का एक गुण है। DoesNotExist से अपवाद inheritsdjango.core.exceptions.ObjectDoesNotExist

आप अपवाद को पकड़ सकते हैं Noneऔर जाने के लिए असाइन कर सकते हैं।

from django.core.exceptions import ObjectDoesNotExist
try:
    go  = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    go = None

33

आप इसके लिए एक सामान्य कार्य बना सकते हैं।

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

नीचे इस तरह का प्रयोग करें:

go = get_or_none(Content,name="baby")

यदि कोई प्रविष्टि मैच सामग्री प्रविष्टि वापस नहीं आएगी तो कोई भी नहीं जाएगा।

ध्यान दें: यदि अपवाद एक से अधिक प्रविष्टि नाम = "बच्चे" के लिए लौटा है, तो यह एकाधिकऑबजेक्ट्स को छोड़ देगा।



14

चीजों को आसान बनाने के लिए, यहाँ मैंने जो कोड लिखा है उसका एक स्निपेट अद्भुत उत्तरों से प्राप्त इनपुट के आधार पर है:

class MyManager(models.Manager):

    def get_or_none(self, **kwargs):
        try:
            return self.get(**kwargs)
        except ObjectDoesNotExist:
            return None

और फिर अपने मॉडल में:

class MyModel(models.Model):
    objects = MyManager()

बस। अब आपके पास MyModel.objects.get () साथ ही MyModel.objetcs.get_or_none () है


7
आयात करना भी न भूलें: django.core.exception से आयात करें ObjectDoesNotExist
Moti Radomski

13

आप existsएक फिल्टर के साथ उपयोग कर सकते हैं :

Content.objects.filter(name="baby").exists()
#returns False or True depending on if there is anything in the QS

यदि आप केवल यह जानना चाहते हैं कि क्या मौजूद है, तो इसके लिए एक विकल्प


4
जब मौजूद एक अतिरिक्त डेटाबेस कॉल का कारण होगा। एक अच्छा विचार नहीं
क्रिस्टोफर

@Christoffer सुनिश्चित नहीं है कि यह एक अतिरिक्त db कॉल क्यों होगा। डॉक्स के अनुसार :Note: If you only want to determine if at least one result exists (and don’t need the actual objects), it’s more efficient to use exists().
अनुपम

2
@Christoffer मुझे लगता है कि आप सही हैं। मैं अब प्रश्न को फिर से पढ़ता हूं और ओपी वास्तव में चाहता है कि वास्तविक वस्तु वापस लौटा दी जाए। इसलिए ऑब्जेक्ट लाने से पहले क्लॉज के exists()साथ उपयोग किया जाएगा, ifजिससे db पर दोहरी मार पड़ेगी । यदि मैं किसी और की मदद करता है, तो मैं अभी भी टिप्पणी चारों ओर रखूंगा।
अनुपम

7

आपके विचारों में विभिन्न बिंदुओं पर अपवादों को संभालना वास्तव में बोझिल हो सकता है। एक कस्टम मॉडल प्रबंधक को परिभाषित करने के बारे में, मॉडल फ़ाइल में, जैसे

class ContentManager(model.Manager):
    def get_nicely(self, **kwargs):
        try:
            return self.get(kwargs)
        except(KeyError, Content.DoesNotExist):
            return None

और फिर सामग्री मॉडल वर्ग में इसे शामिल करें

class Content(model.Model):
    ...
    objects = ContentManager()

इस तरह इसे विचारों में आसानी से देखा जा सकता है

post = Content.objects.get_nicely(pk = 1)
if post:
    # Do something
else:
    # This post doesn't exist

1
मैं वास्तव में इस समाधान को पसंद करता हूं, लेकिन जब यह अजगर 3.6 का उपयोग कर रहा है, तो काम करने में सक्षम नहीं था। एक नोट छोड़ना चाहते थे जो कंटेंट मैनजर में रिटर्न को संशोधित कर return self.get(**kwargs)मेरे लिए काम कर सके। उत्तर के साथ कुछ भी गलत नहीं कहने के लिए, बाद के संस्करणों के साथ इसका उपयोग करने की कोशिश करने वाले किसी भी व्यक्ति के लिए सिर्फ एक टिप (या मेरे साथ काम करने से इसे जो कुछ भी रखा गया है)।
स्कैगज़िला

7

यह उन कष्टप्रद कार्यों में से एक है जिन्हें आप फिर से लागू नहीं करना चाहते हैं:

from annoying.functions import get_object_or_None
#...
user = get_object_or_None(Content, name="baby")

मैंने कोड की जाँच की get_object_or_Noneलेकिन पाया कि यह अभी भी बढ़ा है MultipleObjectsReturnedअगर एक से अधिक ऑब्जेक्ट। इसलिए, उपयोगकर्ता एक के साथ आस-पास विचार कर सकता है try-except(जो फ़ंक्शन में try-exceptपहले से ही है)।
जॉन पैंग

4

यदि आप एक सरल एक-लाइन समाधान चाहते हैं जिसमें अपवाद हैंडलिंग, सशर्त विवरण या Django 1.6+ की आवश्यकता शामिल नहीं है, तो इसके बजाय करें:

x = next(iter(SomeModel.objects.filter(foo='bar')), None)

4

मुझे लगता है कि इसका इस्तेमाल करना बुरा नहीं है get_object_or_404()

from django.shortcuts import get_object_or_404

def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)

यह उदाहरण इसके बराबर है:

from django.http import Http404

def my_view(request):
    try:
        my_object = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404("No MyModel matches the given query.")

आप django के ऑनलाइन दस्तावेज़ में get_object_or_404 () के बारे में अधिक पढ़ सकते हैं ।


2

Django 1.7 के बाद से आप ऐसा कर सकते हैं:

class MyQuerySet(models.QuerySet):

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


class MyBaseModel(models.Model):

    objects = MyQuerySet.as_manager()


class MyModel(MyBaseModel):
    ...

class AnotherMyModel(MyBaseModel):
    ...

"MyQuerySet.as_manager ()" का लाभ यह है कि निम्नलिखित दोनों काम करेंगे:

MyModel.objects.filter(...).get_or_none()
MyModel.objects.get_or_none()

1

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

def get_unique_or_none(model, queryset=None, **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(**kwargs)
    except model.DoesNotExist:
        return None

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

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

1

बिना अपवाद के:

if SomeModel.objects.filter(foo='bar').exists():
    x = SomeModel.objects.get(foo='bar')
else:
    x = None

एक अपवाद का उपयोग करना:

try:
   x = SomeModel.objects.get(foo='bar')
except SomeModel.DoesNotExist:
   x = None

जब अजगर को एक अपवाद का उपयोग करना चाहिए, तो इसके बारे में थोड़ा तर्क है। एक ओर, "अनुमति के लिए क्षमा मांगना अधिक आसान है"। जबकि मैं इस बात से सहमत हूं, मेरा मानना ​​है कि एक अपवाद रहना चाहिए, ठीक है, अपवाद, और "आदर्श मामला" बिना किसी को मार दिए चलना चाहिए।


1

हम Django बिलिन अपवाद का उपयोग कर सकते हैं जो कि नामित मॉडल से जुड़ा हुआ है .DoesNotExist। इसलिए, हमें ObjectDoesNotExistअपवाद आयात करने की आवश्यकता नहीं है ।

इसके बजाय:

from django.core.exceptions import ObjectDoesNotExist

try:
    content = Content.objects.get(name="baby")
except ObjectDoesNotExist:
    content = None

हम यह कर सकते हैं:

try:
    content = Content.objects.get(name="baby")
except Content.DoesNotExist:
    content = None

0

यह Django के get_object_or_404 से एक कॉपीकैट है सिवाय इसके कि विधि कोई भी नहीं लौटाता है। यह अत्यंत उपयोगी है जब हमें only()क्वेरी का उपयोग केवल कुछ क्षेत्रों को पुनः प्राप्त करने के लिए करना होता है। यह विधि एक मॉडल या एक क्वेरी को स्वीकार कर सकती है।

from django.shortcuts import _get_queryset


def get_object_or_none(klass, *args, **kwargs):
    """
    Use get() to return an object, or return None if object
    does not exist.
    klass may be a Model, Manager, or QuerySet object. All other passed
    arguments and keyword arguments are used in the get() query.
    Like with QuerySet.get(), MultipleObjectsReturned is raised if more than
    one object is found.
    """
    queryset = _get_queryset(klass)
    if not hasattr(queryset, 'get'):
        klass__name = klass.__name__ if isinstance(klass, type) else klass.__class__.__name__
        raise ValueError(
            "First argument to get_object_or_none() must be a Model, Manager, "
            "or QuerySet, not '%s'." % klass__name
        )
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        return None

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