38

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?

frederj
  • 1,483
  • 9
  • 20
David542
  • 104,438
  • 178
  • 489
  • 842
  • Well, it seems you already solved your question. Just as an additional argument, use try: ... except (using specific exceptions) is considered a good practice in Python (let alone Django, which follows more or less the same philosophy). – r_31415 Jun 03 '12 at 01:34
  • 3
    `(Model.objects.filter(pk=1) or [None])[0]` is less explicit but sometimes useful also. – okm Jun 03 '12 at 05:27
  • possible duplicate of [In Django, how do I objects.get, but return None when nothing is found?](http://stackoverflow.com/questions/3090302/in-django-how-do-i-objects-get-but-return-none-when-nothing-is-found) – congusbongus Jul 06 '15 at 05:45
  • 1
    I don't really like that it's an unnamed except. What's the specific `Exception` subclass involved here? – Lazerbeak12345 Apr 22 '21 at 18:33
  • 1
    it's `YourModel.DoesNotExist` or `FooBar.DoesNotExist` – Lazerbeak12345 Apr 22 '21 at 20:59

5 Answers5

68

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

ArtOfWarfare
  • 20,617
  • 19
  • 137
  • 193
Gaurav
  • 1,053
  • 10
  • 11
  • 8
    Note that this isn't the same thing, because `get` errors if more than one match is found, whereas this simply returns the first one. – Sasha Chedygov Jul 03 '18 at 22:12
2

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

get_object_or_404(Mode, pk=1)
JoseP
  • 611
  • 3
  • 6
2

How about this?

model_to_find = next(iter(Model.objects.filter(id=1)), None)
allan
  • 153
  • 2
  • 6
0

get_object_or_404

in your model do . . .

@models.permalink
def get_absolute_url(self):
    return "/blog/%s/" self.slug
eusid
  • 769
  • 2
  • 6
  • 18
0

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))
pymen
  • 5,737
  • 44
  • 35