Django: Best way to retrieve object

2019-07-10 04:28发布

问题:

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.

回答1:

Here is the two correct way in my opinion:

  1. Try-except solution (your Scenario1 ):

    try:
        person = Person.objects.get(email="xxx@xxx.xxx")
    except Person.DoesNotExist:
        person= None
    
  2. 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.



回答2:

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")


回答3:

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.