How do I get the object if it exists, or None if it does not exist?

How do I get the object if it exists, or None if it does not exist?

When I ask the model manager to get an object, it raises DoesNotExist when there is no matching object.
go = Content.objects.get(name="baby")

Instead of DoesNotExist, how can I have go be None instead?

Solutions/Answers:

Answer 1:

There is no ‘built in’ way to do this. Django will raise the DoesNotExist exception every time.
The idiomatic way to handle this in python is to wrap it in a try catch:

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

What I did do, is to subclass models.Manager, create a safe_get like the code above and use that manager for my models. That way you can write: SomeModel.objects.safe_get(foo='bar').

Answer 2:

Since django 1.6 you can use first() method like so:

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

Answer 3:

From django docs

get() raises a DoesNotExist exception if an object is not found for the given parameters. This exception is also an attribute of the model class. The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist

You can catch the exception and assign None to go.

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

Answer 4:

You can create a generic function for this.

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

Use this like below:

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

go will be None if no entry matches else will return the Content entry.

Note:It will raises exception MultipleObjectsReturned if more than one entry returned for name=”baby”

Answer 5:

You can do it this way:

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

Now go variable could be either the object you want or None

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

Answer 6:

To make things easier, here is a snippet of the code I wrote, based on inputs from the wonderful replies here:

class MyManager(models.Manager):

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

And then in your model:

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

That’s it.
Now you have MyModel.objects.get() as well as MyModel.objetcs.get_or_none()

Answer 7:

you could use exists with a filter:

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

just an alternative for if you only want to know if it exists

Answer 8:

Handling exceptions at different points in your views could really be cumbersome..What about defining a custom Model Manager, in the models.py file, like

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

and then including it in the content Model class

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

In this way it can be easily dealt in the views i.e.

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

Answer 9:

It’s one of those annoying functions that you might not want to re-implement:

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

Answer 10:

If you want a simple one-line solution that doesn’t involve exception handling, conditional statements or a requirement of Django 1.6+, do this instead:

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

Answer 11:

I think it isn’t bad idea to use 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)

This example is equivalent to:

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.")

You can read more about get_object_or_404() in django online documentation.

Answer 12:

From django 1.7 onwards you can do like:

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):
    ...

The advantage of “MyQuerySet.as_manager()” is that both of the following will work:

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

Answer 13:

Here’s a variation on the helper function that allows you to optionally pass in a QuerySet instance, in case you want to get the unique object (if present) from a queryset other than the model’s all objects queryset (e.g. from a subset of child items belonging to a parent instance):

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

This can be used in two ways, e.g.:

  1. obj = get_unique_or_none(Model, **kwargs) as previosuly discussed
  2. obj = get_unique_or_none(Model, parent.children, **kwargs)

Answer 14:

Without exception:

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

Using an exception:

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

There is a bit of an argument about when one should use an exception in python. On the one hand, “it is easier to ask for forgiveness than for permission”. While I agree with this, I believe that an exception should remain, well, the exception, and the “ideal case” should run without hitting one.

References