Django的过滤器对获取单个对象?(Django filter versus get for si

2019-06-23 17:20发布

我有一些同事在这一场辩论。 有检索在Django对象的首选方法,当你期待只有一个?

这两个明显的方法是:

try:
    obj = MyModel.objects.get(id=1)
except MyModel.DoesNotExist:
    # We have no object! Do something...
    pass

和:

objs = MyModel.objects.filter(id=1)

if len(objs) == 1:
    obj = objs[0]
else:
    # We have no object! Do something...
    pass

第一种方法似乎更行为上是正确的,但使用控制流异常,其可能引入一些开销。 二是更加迂回,但永远不会引发异常。

任何想法上的这些最好? 哪个更有效?

Answer 1:

get()是专门为这种情况提供。 用它。

选项2几乎是如何精确的get()方法在Django实际执行,所以不应该有“表演”的区别(以及你想它表明您违反程序设计的基本规则的事实,即尝试它甚至被写入及异形之前优化代码 - 直到你的代码,并可以运行它,你不知道这将如何执行,并试图在此之前,以优化是痛苦的路径)。



Answer 2:

你可以安装一个叫做模块Django的烦人 ,然后做到这一点:

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


Answer 3:

1是正确的。 在Python异常具有相同的开销来一回。 为了简化证明你可以看看这个 。

2这是Django的在后端做。 get电话filter ,如果没有项目被发现抛出一个异常,或者一个以上的对象中找到。



Answer 4:

我有点迟到了,但与Django的1.6存在的first()上查询集方法。

https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.first


如果不存在匹配的对象,则返回由查询集,或无匹配的第一个对象。 如果查询集没有定义排序,然后将查询集自动由主键排序。

例:

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


Answer 5:

我不能使用Django的任何经验,但选项#1讲清楚告诉你所要求的1个对象的系统,而第二个选项没有。 这意味着,如果你在过滤的属性不保证是唯一的选项#1可以更轻松地高速缓存或数据库索引的优势,尤其是。

此外(再次,猜测),第二个选项可能会由于过滤器()调用创建某种结果集合或迭代器对象能够正常返回许多行。 你会绕过这个以get()。

最后,第一个选项是既短,省去了额外的临时变量 - 只有微小的差别,但每一个小小的帮助。



Answer 6:

为什么所有的工作? 替换4行1项内置的快捷方式。 (这确实它自己的try /除外。)

from django.shortcuts import get_object_or_404

obj = get_object_or_404(MyModel, id=1)


Answer 7:

关于异常的一些更多的信息。 如果他们不提高,他们的成本几乎为零。 因此,如果你知道你可能将有结果,使用异常,因为使用条件表达式你付出检查每一次,不管什么成本。 在另一方面,他们花费多一点比当他们提出了一个条件表达式,因此,如果您希望不要有一些频率的结果(比如工作时间的30%,如果没有记错),条件检查证明是有点便宜。

但是,这是Django的ORM,也可能是往返到数据库,甚至是缓存的结果,很可能主宰的性能特点,因此有利于可读性,在这种情况下,你希望只有一个结果,使用get()



Answer 8:

我这个问题打了一下,发现选项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

执行一个查询的等效版本是:

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]

通过切换到这种做法,我能够大幅降低查询我的应用程序执行的数量。



Answer 9:

有趣的问题,但对我的选择#2恶臭过早的优化。 我不知道这是更好的性能,但选择#1肯定的外观和感觉更Python给我。



Answer 10:

我提出一个不同的设计。

如果你想在一个可能的结果执行功能,您可以从查询集衍生,像这样: http://djangosnippets.org/snippets/734/

其结果是相当真棒,例如,您可以:

MyModel.objects.filter(id=1).yourFunction()

在这里,过滤器返回一个空查询集或单个项目一个查询集。 您的自定义查询集功能也可链接的,可重复使用。 如果要执行它的所有条目: MyModel.objects.all().yourFunction()

他们也是理想的用作在管理界面操作:

def yourAction(self, request, queryset):
    queryset.yourFunction()


Answer 11:

选项1是更优雅,但一定要使用try..except。

从我自己的经验,我可以告诉你,有时候你肯定是不可能有一个以上的匹配对象在数据库中,仍然会有两个......(当然,除了通过主键获取对象时)。



文章来源: Django filter versus get for single object?