Cor*_*ory 137 django django-models django-queryset
我和一些同事正在讨论这个问题.当你期望只有一个对象时,有没有一种首选的方法来检索Django中的对象?
两个明显的方法是:
try:
obj = MyModel.objects.get(id=1)
except MyModel.DoesNotExist:
# We have no object! Do something...
pass
Run Code Online (Sandbox Code Playgroud)
和
objs = MyModel.objects.filter(id=1)
if len(objs) == 1:
obj = objs[0]
else:
# We have no object! Do something...
pass
Run Code Online (Sandbox Code Playgroud)
第一种方法似乎在行为上更正确,但在控制流中使用异常可能会引入一些开销.第二个更环形,但不会引发异常.
关于哪一个更好的想法?哪个更有效率?
Jam*_*ett 167
get()是专门为这种情况提供的.用它.
选项2几乎就是如何get()在Django中实际实现该方法,所以不应该存在"性能"差异(而且你正在考虑它的事实表明你违反了编程的一个基本规则,即试图甚至在编写和分析之前优化代码 - 直到你拥有代码并运行它,你不知道它将如何执行,并且在此之前尝试优化是一条痛苦的道路.
pri*_*stc 29
您可以安装一个名为django-annoying的模块,然后执行以下操作:
from annoying.functions import get_object_or_None
obj = get_object_or_None(MyModel, id=1)
if not obj:
#omg the object was not found do some error stuff
Run Code Online (Sandbox Code Playgroud)
Bas*_*Ben 10
我参加派对有点晚了,但是对于Django 1.6,查询集上有first()方法.
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.first
返回查询集匹配的第一个对象,如果没有匹配的对象,则返回None.如果QuerySet没有定义排序,则主键会自动排序查询集.
例:
p = Article.objects.order_by('title', 'pub_date').first()
Note that first() is a convenience method, the following code sample is equivalent to the above example:
try:
p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
p = None
Run Code Online (Sandbox Code Playgroud)
我不能说任何Django的经验,但选项#1明确告诉系统你要求1个对象,而第二个选项没有.这意味着选项#1可以更轻松地利用缓存或数据库索引,尤其是在您要过滤的属性不能保证唯一的情况下.
另外(再次推测)第二个选项可能必须创建某种结果集合或迭代器对象,因为filter()调用通常可以返回许多行.你用get()绕过了这个.
最后,第一个选项更短,省略了额外的临时变量 - 只是一个微小的差异,但每一点都有帮助.
为什么这一切都有效?用1个内置快捷方式替换4行.(这有自己的尝试/除外.)
from django.shortcuts import get_object_or_404
obj = get_object_or_404(MyModel, id=1)
Run Code Online (Sandbox Code Playgroud)
有关异常的更多信息.如果他们没有成长,他们几乎没有任何成本.因此,如果您知道可能会有结果,请使用异常,因为使用条件表达式无论如何都要支付每次检查的成本.另一方面,当它们被提升时,它们比条件表达式花费更多,所以如果你期望没有某个频率的结果(例如,30%的时间,如果内存服务),则条件检查结果要便宜一点.
但这是Django的ORM,可能是数据库的往返,甚至是缓存的结果,可能会主导性能特征,所以在这种情况下支持可读性,因为你期望只有一个结果,使用get().
我稍微研究了一下这个问题,发现选项 2 执行两个 SQL 查询,这对于这样一个简单的任务来说是过多的。看我的注释:
objs = MyModel.objects.filter(id=1) # This does not execute any SQL
if len(objs) == 1: # This executes SELECT COUNT(*) FROM XXX WHERE filter
obj = objs[0] # This executes SELECT x, y, z, .. FROM XXX WHERE filter
else:
# we have no object! do something
pass
Run Code Online (Sandbox Code Playgroud)
执行单个查询的等效版本是:
items = [item for item in MyModel.objects.filter(id=1)] # executes SELECT x, y, z FROM XXX WHERE filter
count = len(items) # Does not execute any query, items is a standard list.
if count == 0:
return None
return items[0]
Run Code Online (Sandbox Code Playgroud)
通过改用这种方法,我能够大幅减少应用程序执行的查询数量。
| 归档时间: |
|
| 查看次数: |
80410 次 |
| 最近记录: |