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

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?

24 Answers

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

14

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

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

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

You should handle it on the data model to avoid this kind of error but you may prefer to log it at run time like this:

def get_or_none(classmodel, **kwargs): try: return classmodel.objects.get(**kwargs) except classmodel.MultipleObjectsReturned as e: print('ERR====>', e) except classmodel.DoesNotExist: return None 
1

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 

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:

1

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()

2

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

3

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

Maybe is better you use:

User.objects.filter(username=admin_username).exists() 
1

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 
1

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) 

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.

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() 
1

This is a copycat from Django's get_object_or_404 except that the method returns None. This is extremely useful when we have to use only() query to retreive certain fields only. This method can accept a model or a queryset.

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 

I use Django 2.2.16. And this is how I solve this problem:

from typing import Any from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.db.models.base import ModelBase from django.db.models.manager import Manager class SManager(Manager): def get_if_exist(self, *args: Any, **kwargs: Any): try: return self.get(*args, **kwargs) except ObjectDoesNotExist: return None class SModelBase(ModelBase): def _prepare(cls): manager = SManager() manager.auto_created = True cls.add_to_class("objects", manager) super()._prepare() class Meta: abstract = True class SModel(models.Model, metaclass=SModelBase): managers = False class Meta: abstract = True 

And after that, in every models, you just need to import in:

from custom.models import SModel class SUser(SModel): pass 

And in views, you can call like this:

SUser.objects.get_if_exist(id=1) 

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)
0

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.

We can use Django builtin exception which attached to the models named as .DoesNotExist. So, we don't have to import ObjectDoesNotExist exception.

Instead doing:

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

We can do this:

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

I was facing with the same problem too. It's hard to write and read try-except for each time when you want to get an element from your model as in @Arthur Debert's answer. So, my solution is to create an Getter class which is inherited by the models:

class Getter: @classmethod def try_to_get(cls, *args, **kwargs): try: return cls.objects.get(**kwargs) except Exception as e: return None class MyActualModel(models.Model, Getter): pk_id = models.AutoField(primary_key=True) ... 

In this way, I can get the actual element of MyActualModel or None:

MyActualModel.try_to_get(pk_id=1) 

Simple way:

if query.exists(): do something....

or

if query.exists() is False: do something...

I prefer this method without using exceptions. It also handles multiple objects as well as no objects.

go_list = Content.objects.filter(name="baby") if (len(go_list) == 1): go = go_list[0] else: go = None # optionally do other things if there are multiple objects / no objects. 

What if something like this?

go = (Content.objects.filter(name="value") or [None])[0] 

As it has been mentioned in other answers, you can use

filter(**kwargs).first()

The issue with this method is it never throws a MultipleObjectsReturned error if the query returns multiple objects. This may not always be desirable. Assume you have the following database table

id first_name last_name
1 Keenen Wayans
2 Marlon Wayans
3 Shawn Wayans

Person.objects.filter(last_name="Wayans").first()

will always return Keenen Wayans. The user will never know there are other 'Wayans'

If you don't like this, below is my reimplementation of Django's shortcut method get_object_or_404. If no object is found, it returns None, but if the query returns multiple objects, it throws a MultipleObjectsReturned exception. I would rather handle MultipleObjectsReturned exception, instead of returning a bogus value to the user.

In a separate file called shortcuts.py, create a method called get_object_or_none.

def get_object_or_none(klass, *args, **kwargs): """ Use get() to return an object, or returns None if the object does not exist instead of throwing an exception. 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 = klass._default_manager.all() if hasattr(klass, "_default_manager") else 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 

Then in views.py

from myapp.shortcuts import get_object_or_none person = get_object_or_none(Person, first_name='Shawn', last_name='Wayans') #person is 'Shawn Wayans' person = get_object_or_none(Person, last_name='Hendrix') #person is None as database has no person with last name 'Hendrix' person = get_object_or_none(Person, last_name='Wayans') #throws 'MultipleObjectsReturned' error since multiple persons returned. 

How about a slice? It will parse to a limit 1.

go = Content.objects.filter(name="baby")[0] 
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like