2

Lets say I want to get a record that match a value and I have 2 approaches to do it:

First:

try:
  obj = Model.objects.get(field = value)
except
  pass

Second:

if Model.objects.filter(field = value).count() > 0:
  obj = Model.objects.filter(field_value)[0]

Lets put the code comments aside,which way should I use or which one do you prefer to read? The first one seems faster because only 1 DB look up, but the second way seems a bit more readable, but requires 2 DB look ups.

9
  • Use get() instead of filter() if you only want a single object Commented Nov 14, 2012 at 0:30
  • 1
    This doc link might be relevant. Commented Nov 14, 2012 at 0:32
  • Also, are you sure filter throws an exception? You might not need that try/except. Commented Nov 14, 2012 at 0:33
  • at the end of the statement I am trying to get the first record, it will throw out of index exception Commented Nov 14, 2012 at 0:34
  • @NoPyGod, the filter won't throw an exception but the [0] that accesses the first result of the queryset for assignment will. Commented Nov 14, 2012 at 0:34

2 Answers 2

11

The first is preferred in Python, based on the EAFP design principle ("Easier to Ask Forgiveness than Permission"). Aside from speed, one advantage of this system is that there is no race condition -- in the second example, if other concurrent access to the database changes the results between the execution of the first and the second line of code, then your results will be inconsistent.

Depending on your use of transactions, the race condition possibility may be a non-issue, but in general EAFP is a prominent design pattern in Python and experienced Python coders will not have any trouble reading code in that form.

ETA: Oh, and I forgot: don't use except: (you do need the colon). Use except IndexError: or whatever other specific exception you are looking for. That way if you get a totally unexpected error like a failure to reach the database, it will propagate through and not be hidden. You don't want a situation where you later write code counting on the exception being thrown to mean "there are no results" and instead the system is trying to tell you "the database is down".

Sign up to request clarification or add additional context in comments.

Comments

0

How about

matches = Model.objects.filter(field=value)[:1]
obj = matches[0] if matches else None

The query will only be evaluated once (when evaluating matches in the if part of the conditional expression), and this is used both for the emptiness check and retrieving the result. Note the slicing to limit the number of returned objects.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.