我经常发现自己想从 Django 中的查询集中获取第一个对象,或者如果没有,则返回 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 测试时,这是一件非常耗费内存的事情。
如何仅通过一个数据库调用而不用异常对象搅动内存来做到这一点?
len()
,始终使用 .count()
。
first()
和 last()
便利方法:docs.djangoproject.com/en/dev/ref/models/querysets/#first
Django 1.6 (released Nov 2013) 引入了 convenience methods first()
和 last()
,如果查询集没有返回任何对象,它们会吞下生成的异常并返回 None
。
您可以使用 array slicing:
Entry.objects.all()[:1].get()
可与 .filter()
一起使用:
Entry.objects.filter()[:1].get()
您不希望首先将其转换为列表,因为这将强制对所有记录进行完整的数据库调用。只需执行上述操作,它只会拉第一个。您甚至可以使用 .order_by()
来确保获得您想要的第一个。
请务必添加 .get()
,否则您将返回 QuerySet 而不是对象。
Entry.objects.all()[0]
有什么不同??
r = list(qs[:1])
if r:
return r[0]
return None
LIMIT 1
添加到查询中,而且我不知道您能做得比这更好。但是,QuerySet
中的 __nonzero__
在内部实现为 try: iter(self).next() except StopIteration: return false...
,因此它不会逃避异常。
QuerySet.__nonzero__()
永远不会被调用,因为 QuerySet
在检查真实性之前已转换为 list
。然而,其他例外情况仍可能发生。
StopIteration
异常。
__iter__
以获取新的迭代器对象并调用它的 next
方法,直到 StopIteration
被抛出。所以肯定会有一个例外的地方;)
现在,在 Django 1.9 中,您有用于查询集的 first()
方法。
YourModel.objects.all().first()
这是比 .get()
或 [0]
更好的方法,因为如果查询集为空,它不会引发异常,因此,您无需使用 exists()
进行检查
这也可以工作:
def get_first_element(MyModel):
my_query = MyModel.objects.all()
return my_query[:1]
如果为空,则返回一个空列表,否则返回列表中的第一个元素。
如果您打算经常获取第一个元素 - 您可以在这个方向扩展 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()
它可以是这样的
obj = model.objects.filter(id=emp_id)[0]
或者
obj = model.objects.latest('id')
您应该使用 django 方法,例如存在。它在那里供您使用。
if qs.exists():
return qs[0]
return None
first()
和last()
对查询强制执行ORDER BY
子句。这将使结果具有确定性,但很可能会减慢查询速度。ORDER BY
,而[:1]
避免了这一点。