我经常发现自己想要从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-test时,这是一项非常占用内存的工作。
我该如何仅用一个数据库调用就可以做到这一点,而又不浪费带有异常对象的内存?
“很多时候创建一个异常对象,这是非常耗费内存的事情”-如果您担心创建一个额外的异常,那么您做错了,因为Python到处都使用异常。您是否实际针对您的情况进行了基准测试,确定它占用大量内存?
—
lqc 2012年
@Leopd如果您实际上以任何方式(或至少是注释)对基准进行了基准测试,您会知道它并没有更快。实际上,它可能会比较慢,因为您创建了一个额外的列表只是为了将其丢弃。与调用python函数或首先使用Django的ORM的成本相比,这仅仅是花生米!一次调用filter()会比引发异常慢很多很多倍(仍然会引发异常,因为这就是迭代器协议的工作原理!)。
—
lqc
您的直觉是正确的,即性能差异很小,但是您的结论是错误的。我确实做了一个基准测试,实际上可以接受的答案要快得多。去搞清楚。
—
Leopd 2012年
对于使用Django 1.6的人们,他们终于添加了
—
Wei Yen
first()
和last()
便捷方法:docs.djangoproject.com/en/dev/ref/models/querysets/#first
len()
在querysets上使用,请始终使用.count()
。