Lets assume that I have a class Person
with a field email
. I want to get a single record based on queryset and assign it to variable person
. Sadly I cannot do
person = Person.objects.filter(email="xxx@xxx.xxx")[0]
because I might get an exception. So:
Scenario 1: Include the above code in a try-except.
Scenario 2 (which I'm currently using):
person_arr = Person.objects.filter(email="xxx@xxx.xxx")
if person_arr.exists():
person = person_arr[0]
....
Scenario 3
for person in Person.objects.filter(email="xxx@xxx.xxx"):
....
Scenario 4: You suggest something else.
Here is the two correct way in my opinion:
Try-except solution (your Scenario1 ):
try:
person = Person.objects.get(email="xxx@xxx.xxx")
except Person.DoesNotExist:
person= None
Django 1.6+ solution using first() (recommended):
person = Person.objects.filter(email="xxx@xxx.xxx").first()
This is from the documentation:
Returns the first object matched by the queryset, or None if there is
no matching object. If the QuerySet has no ordering defined, then the
queryset is automatically ordered by the primary key.
This solution will allow you to do whatever you want if the object does not exist.
Note that this will work only if no emails are duplicated which makes total sense in this case.
You can use get_object_or_404
instead, doing something like:
from django.shortcuts import get_object_or_404
person = get_object_or_404(Person, email="xx@xxx.com")
There's a special shortcut - get_object_or_404()
.
Equivalent of:
from django.http import Http404
def my_view(request):
try:
my_object = MyModel.objects.get(pk=1)
except MyModel.DoesNotExist:
raise Http404("No MyModel matches the given query.")
Why it's better? If you have not found an object then 404 is an appoproate answer. This shortcut allows you to keep code cleaner.