Reputation: 110093
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
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
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
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
Reputation: 343
How about this?
model_to_find = next(iter(Model.objects.filter(id=1)), None)
Upvotes: 3
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
Reputation: 769
get_object_or_404
in your model do . . .
@models.permalink
def get_absolute_url(self):
return "/blog/%s/" self.slug
Upvotes: 0