从django中的queryset中获得第一个对象的最快方法?

我经常发现自己想从Django的queryset中获取第一个对象,如果没有的话返回None。有很多方法都可以做到这一点。但我想知道哪种是性能最好的。

qs = MyModel.objects.filter(blah = blah)
if qs.count() > 0:
return qs[0]
else:
return None

这会导致两次数据库调用吗?这似乎是浪费。这个会快一点吗?

qs = MyModel.objects.filter(blah = blah)
if len(qs) > 0:
return qs[0]
else:
return None

另一种选择是:

qs = MyModel.objects.filter(blah = blah)
try:
return qs[0]
except IndexError:
return None

这将生成一个单独的数据库调用,这很好。但是需要在很多时候创建一个异常对象,当您真正需要的只是一个微不足道的if-test时,这是一件非常占用内存的事情。

我如何做到这一点,只有一个数据库调用,而不搅动内存与异常对象?

312063 次浏览
r = list(qs[:1])
if r:
return r[0]
return None

你可以使用数组切片:

Entry.objects.all()[:1].get()

可以与.filter()一起使用:

Entry.objects.filter()[:1].get()

您不希望首先将其转换为列表,因为这将强制对所有记录进行完整的数据库调用。只要做上面的操作,它就只会拉第一个。你甚至可以使用.order_by()来确保你得到你想要的第一个。

一定要添加.get(),否则你将得到一个QuerySet而不是一个对象。

如果你计划经常获取第一个元素,你可以沿着这个方向扩展QuerySet:

class FirstQuerySet(models.query.QuerySet):
def first(self):
return self[0]




class ManagerWithFirstQuery(models.Manager):
def get_query_set(self):
return FirstQuerySet(self.model)

像这样定义模型:

class MyModel(models.Model):
objects = ManagerWithFirstQuery()

像这样使用它:

 first_object = MyModel.objects.filter(x=100).first()

你应该使用django的方法,比如exists。它就在那里等着你去使用。

if qs.exists():
return qs[0]
return None

它可以是这样的

obj = model.objects.filter(id=emp_id)[0]

obj = model.objects.latest('id')

Django 1.6(2013年11月发布)引入了方便的方法 first()last(),它们会接收产生的异常,如果查询集不返回对象,则返回None

现在,在Django 1.9中,你有first()方法用于查询集。

YourModel.objects.all().first()

这是一种比.get()[0]更好的方法,因为如果queryset为空,它不会抛出异常。因此,您不需要使用exists()进行检查

这也可以奏效:

def get_first_element(MyModel):
my_query = MyModel.objects.all()
return my_query[:1]

如果为空,则返回一个空列表,否则返回列表中的第一个元素。