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

PythonDjangoDjango Queryset

Python Problem Overview


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?

Python Solutions


Solution 1 - Python

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

Solution 2 - Python

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

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

Solution 3 - Python

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

Solution 4 - Python

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

Solution 5 - Python

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

Solution 6 - Python

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

Solution 7 - Python

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

Solution 8 - Python

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

Solution 9 - Python

Maybe is better you use:

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

Solution 10 - Python

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

Solution 11 - Python

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)

Solution 12 - Python

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.

Solution 13 - Python

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

Solution 14 - Python

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

Solution 15 - Python

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)

Solution 16 - Python

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.

Solution 17 - Python

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

Solution 18 - Python

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)

Solution 19 - Python

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)

Solution 20 - Python

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTIMEXView Question on Stackoverflow
Solution 1 - PythonArthur DebertView Answer on Stackoverflow
Solution 2 - PythonFeroxTLView Answer on Stackoverflow
Solution 3 - PythonAmarghoshView Answer on Stackoverflow
Solution 4 - PythonRanju RView Answer on Stackoverflow
Solution 5 - PythonGauravView Answer on Stackoverflow
Solution 6 - PythonMoti RadomskiView Answer on Stackoverflow
Solution 7 - PythonRyan SaxeView Answer on Stackoverflow
Solution 8 - PythonmknechtView Answer on Stackoverflow
Solution 9 - PythonJonathan SouzaView Answer on Stackoverflow
Solution 10 - PythonAdil MalikView Answer on Stackoverflow
Solution 11 - PythonblhsingView Answer on Stackoverflow
Solution 12 - PythonMohammad RezaView Answer on Stackoverflow
Solution 13 - PythonVinayak KaniyarakkalView Answer on Stackoverflow
Solution 14 - PythonSandeep BalagopalView Answer on Stackoverflow
Solution 15 - PythonGaryView Answer on Stackoverflow
Solution 16 - PythonKonstantin SchubertView Answer on Stackoverflow
Solution 17 - PythonzakiakhmadView Answer on Stackoverflow
Solution 18 - PythonErsel ErView Answer on Stackoverflow
Solution 19 - PythonSihcView Answer on Stackoverflow
Solution 20 - PythonBruce MartinView Answer on Stackoverflow