Fastest way to get the first object from a queryset in django?
Often I find myself wanting to get the first object from a queryset in Django, or return None
if there aren't any. There are lots of ways to do this which all work. But I'm wondering which is the most performant.
qs = MyModel.objects.filter(blah 开发者_JAVA百科= blah)
if qs.count() > 0:
return qs[0]
else:
return None
Does this result in two database calls? That seems wasteful. Is this any faster?
qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
return qs[0]
else:
return None
Another option would be:
qs = MyModel.objects.filter(blah = blah)
try:
return qs[0]
except IndexError:
return None
This generates a single database call, which is good. But requires creating an exception object a lot of the time, which is a very memory-intensive thing to do when all you really need is a trivial if-test.
How can I do this with just a single database call and without churning memory with exception objects?
Django 1.6 (released Nov 2013) introduced the convenience methods first()
and last()
which swallow the resulting exception and return None
if the queryset returns no objects.
You can use array slicing:
Entry.objects.all()[:1].get()
Which can be used with .filter()
:
Entry.objects.filter()[:1].get()
You wouldn't want to first turn it into a list because that would force a full database call of all the records. Just do the above and it will only pull the first. You could even use .order_by()
to ensure you get the first you want.
Be sure to add the .get()
or else you will get a QuerySet back and not an object.
Now, in Django 1.9 you have first()
method for querysets.
YourModel.objects.all().first()
This is a better way than .get()
or [0]
because it does not throw an exception if queryset is empty, Therafore, you don't need to check using exists()
r = list(qs[:1])
if r:
return r[0]
return None
This could work as well:
def get_first_element(MyModel):
my_query = MyModel.objects.all()
return my_query[:1]
if it's empty, then returns an empty list, otherwise it returns the first element inside a list.
If you plan to get first element often - you can extend QuerySet in this direction:
class FirstQuerySet(models.query.QuerySet):
def first(self):
return self[0]
class ManagerWithFirstQuery(models.Manager):
def get_query_set(self):
return FirstQuerySet(self.model)
Define model like this:
class MyModel(models.Model):
objects = ManagerWithFirstQuery()
And use it like this:
first_object = MyModel.objects.filter(x=100).first()
It can be like this
obj = model.objects.filter(id=emp_id)[0]
or
obj = model.objects.latest('id')
You should use django methods, like exists. Its there for you to use it.
if qs.exists():
return qs[0]
return None
精彩评论