107

I need to verify if an object exists and return the object, then based on that perform actions. What's the right way to do it without returning a 404?

try:
    listing = RealEstateListing.objects.get(slug_url = slug)
except:
    listing = None

if listing:
Milan Cermak
  • 7,476
  • 3
  • 44
  • 59
Rasiel
  • 2,823
  • 6
  • 31
  • 37
  • 1
    Rasiel, can I suggest that you consider accepting the other answer? It seems to be the correct way to do this, and has been upvoted quite a bit more than the accepted answer. – Azendale Nov 10 '15 at 04:39
  • 1
    I can consider it, however exists was introduced in Django 1.2 which was released May 17 2010, If you notice my question was submitted in 09... this was the correct answer at the time. If Exists() is now considered the best way to do it, I guess it would be semantically correct to choose the second answer, right? – Rasiel Nov 12 '15 at 03:38
  • Rasiel, it makes sense that that was the correct answer at the time. But the stackoverflow sites seem to be as much about building a set of good/official questions with the best answers as the sites are finding solutions to people's problems. Hence my suggestion to select what is now the "officially correct" answer. – Azendale Nov 12 '15 at 05:01
  • The `if listing:` should be an `else:`. – Chronial Nov 19 '15 at 16:48

4 Answers4

228

You can also do:

if not RealEstateListing.objects.filter(slug_url=slug).exists():
    # do stuff...

Sometimes it's more clear to use try: except: block and other times one-liner exists() makes the code looking clearer... all depends on your application logic.

daaawx
  • 3,273
  • 2
  • 17
  • 16
zzart
  • 11,207
  • 5
  • 52
  • 47
128

I would not use the 404 wrapper if you aren't given a 404. That is misuse of intent. Just catch the DoesNotExist, instead.

try:
    listing = RealEstateListing.objects.get(slug_url=slug)
except RealEstateListing.DoesNotExist:
    listing = None
ironfroggy
  • 7,991
  • 7
  • 33
  • 44
  • +1: Yes, this is a better solution than the accepted one, if you don't want the 404. – Carl Meyer Mar 13 '09 at 18:25
  • yap, this seems to be the better solution – Rasiel Mar 26 '09 at 05:10
  • 3
    This solution works better than `exists()` if you need to do something with the object. – SaeX Nov 14 '15 at 20:41
  • 2
    I like to add `values_list('id', flat=True)`. if I need to just see if exists `listing = RealEstateListing.objects.values_list('id', flat=True).get(slug_url=slug)` – erajuan Jan 27 '16 at 17:12
  • What I find strange about this syntax is that `RealEstateListing.DoesNotExist` is referring to the model, and not the object itself. Why is it not `RealEstateListing.objects.get(slug_url=slug).DoesNotExist`? – Max Vallee Jun 05 '20 at 18:11
9
listing = RealEstateListing.objects.filter(slug_url=slug).first() 
Henrik Heino
  • 395
  • 4
  • 9
  • 2
    This is the best solution if you need to use the potential object later, since it only requires one assignment, and it avoids having to use a try/except block. Note that you can test for existence later simply with `if listing:` – Michael Hays Nov 10 '17 at 21:42
  • Avoiding try/except is bad practice. One of the most important aspects of Software Development is the availability to control Exceptions, this to be able to provide a good user experience. Let people know when something is not working properly. Second; if you want to test the existence of a QuerySet use .exists() otherwise is an object. Test for existence with their primary key.... if object.pk: // run code() This query is way faster than retrieving all data of the object. You just want to know if exists. – Wolfgang Leon Sep 27 '18 at 17:56
  • 2
    There already was a solutions using try/except and `.exists()`. I think it is good idea in SO to have multiple different answers how to do things. Maybe this is better for those that also want to use the object if it exists. I would not make any rules if try/except should be avoided or not. Sometimes its good, and sometimes it's bad for example if you just want to make very compact code. – Henrik Heino Oct 19 '18 at 08:36
0

I would do it as simple as follows:

listing = RealEstateListing.objects.filter(slug_url=slug)
if listing:
    # do stuff

I don't see a need for try/catch. If there are potentially several objects in the result, then use first() as shown by user Henrik Heino

Greg Holst
  • 874
  • 10
  • 23