David542
David542

Reputation: 110093

Model.objects.get() or None

Is there a way to accomplish the following in one call:

Model.objects.get(id=1) else None

The only way I've found a way to do this is by doing:

try:
    object = Model...
except:
    object = None

Is there a way to do this in a single call in django?

Update: There does not seem to be a way to do this other than in a try/except block, but here is a better answer: In Django, how do I objects.get, but return None when nothing is found?

Upvotes: 47

Views: 65512

Answers (6)

David Winiecki
David Winiecki

Reputation: 4203

As others have pointed out, MyModel.objects.filter(id=1).first() will not raise an error if more than one model matches the query, which may be undesirable in some cases.

If you want an error to be raised in that case then this is another way:

(obj,) = MyModel.objects.filter(id=1) or [None]

If there is more than one model that matches the query, then this error is raised:

ValueError: too many values to unpack (expected 1)

But this probably isn't the best way to do this in production. I think it's better to be explicit and use try and except.

Upvotes: 2

JoseP
JoseP

Reputation: 631

If you are using it in a web request, and you want to return a 404 if the object does not exist you can use

from django.shortcuts import get_object_or_404
get_object_or_404(Mode, pk=1)

Upvotes: 4

pymen
pymen

Reputation: 6539

i think better to reuse Django functionality as much as possible, and django has 99% similar func get_object_or_404 which just raises Http404

from django.shortcuts import get_object_or_404

def get_or_none(model_or_qs, **kwargs):
    try:
        return get_object_or_404(model_or_qs, **kwargs)
    except Http404:
        return None

Some tests cases that shows that code can be used for Model, Queryset, RelatedManager

[in tests one User can Have multiple Contacts]

    @test_for(get_or_none)
    def test_get_or_none_for_model(self):
        self.assertEqual(self.user, get_or_none(User, pk=self.user.pk))
        self.assertEqual(None, get_or_none(User, pk=777))

    @test_for(get_or_none)
    def test_get_or_none_for_queryset_and_manager(self):
        contact = ContactFactory(user=self.user)
        self.assertEqual(self.user, get_or_none(User.objects, pk=self.user.pk))
        self.assertEqual(self.user, get_or_none(User.objects.all(), pk=self.user.pk))
        self.assertEqual(contact, get_or_none(Contact.objects.filter(user=self.user)))
        self.assertEqual(contact, get_or_none(self.user.contacts))
        self.assertEqual(None, get_or_none(User.objects.all(), pk=777))
        self.assertEqual(None, get_or_none(self.user.contacts, pk=777))

Upvotes: 4

allan
allan

Reputation: 343

How about this?

model_to_find = next(iter(Model.objects.filter(id=1)), None)

Upvotes: 3

Gaurav
Gaurav

Reputation: 1175

How about this:

obj = Model.objects.filter(id=1).first()

now if no object with id=1 exists obj would be None

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

Upvotes: 78

eusid
eusid

Reputation: 769

get_object_or_404

in your model do . . .

@models.permalink
def get_absolute_url(self):
    return "/blog/%s/" self.slug

Upvotes: 0

Related Questions