在Django中检查空的查询集


182

建议的检查查询是否返回任何结果的惯用法是什么?
例:

orgs = Organisation.objects.filter(name__iexact = 'Fjuk inc')
# If any results
    # Do this with the results without querying again.
# Else, do something else...

我想有几种不同的检查方法,但是我想知道一个有经验的Django用户将如何做。文档中的大多数示例只是忽略了什么都没有发现的情况...

Answers:


204
if not orgs:
    # Do this...
else:
    # Do that...

5
这在文档中似乎也是首选的,例如:docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7
Wtower

1
@Wtower如果过滤表达式未命中任何记录,则所引用的代码具有使合同增加404的作用;如果有记录,则所涉及的代码将产生list结果的a 。那里的代码将只访问数据库一次。如果他们曾经使用过exist()count()首先要检查是否要返回记录,那么他们将两次访问数据库(一次检查一次,一次获取记录)。这是一个特定的情况。这并不意味着在一般情况下,知道查询是否将返回记录的首选方法是使用doif queryset:...
Louis

1
@Louis我所引用的代码只是一个示例,其中包含一行if not my_objects:来说明这是他们在文档中的操作方式。其他所有内容都无关紧要,所以我不明白你的意思。他们也可以进行一千次查询,但这仍然完全无关紧要,因为这不是答案的重点,我明确表示同意。
Wtower

1
@Wtower也就是说只是一个解释如何的get_object_or_404作品,检查任何元素是否在查询集存在的首选方式。在queryset上执行list()将获取一个queryset上的每个对象,如果返回的行很多,那将比两次查询更为糟糕。
minmaxavg 2015年

1
有关更详细的答案,请参见下面的@ leonid-shvechikov的答案:.exists()如果不会评估qs,则使用效率更高。
吉瓦尔

191

从1.2版开始,Django具有QuerySet。最有效的exist()方法:

if orgs.exists():
    # Do this...
else:
    # Do that...

但是,无论如何,如果要评估QuerySet,最好使用:

if orgs:
   ...

有关更多信息,请阅读QuerySet.exists()文档


.exists()仅用于.filter(),. get()是否有用?
轧辊

.get不返回查询集。它返回一个对象。所以谷歌为此
Aseem

只有拥有大型QuerySet时,它的效率才会明显提高:docs.djangoproject.com/en/2.1/ref/models/querysets/#exists
Nathan Jones

15

如果您有大量的对象,这可能(有时)要快得多:

try:
    orgs[0]
    # If you get here, it exists...
except IndexError:
    # Doesn't exist!

在一个我正在使用大型数据库的项目中,时间not orgs是400毫秒以上,orgs.count()。在我最常见的用例(有结果的情况)中,此技术通常会将其降至20ms以下。(我发现一个案例是6。)

当然,它可能更长一些,具体取决于数据库查找结果所需的距离。甚至更快,如果能够快速找到它的话;YMMV。

编辑:这经常是慢orgs.count()如果结果是找不到的,特别是如果你筛选的条件是难得的一个; 因此,它在需要确保视图存在或抛出Http404的视图函数中特别有用。(人们希望在那里,人们要求的URL经常存在。)


10

要检查查询集的空度:

if orgs.exists():
    # Do something

或者您可以检查查询集中的第一项,如果不存在则将返回None

if orgs.first():
    # Do something

6
if orgs.exists()在此答案之前的大约5年内提供了答案。这个答案带来的唯一一件事是可能是新的是if orgs.first()。(即使这是值得商bat的:它与大约5年前的orgs[0] 建议也有很大不同吗?)您应该制定答案的这一部分:什么时候要这样做而不是较早提出的其他解决方案?
2015年

9

最有效的方法(在Django 1.2之前)是:

if orgs.count() == 0:
    # no results
else:
    # alrigh! let's continue...

5
.exists()似乎更加有效
dzida 2012年

5
除了在我的评论后几个月添加了.exists(),并且在大约8个月后发布了Django 1.2(包含该API)。但是,感谢您的不赞成票,也不想麻烦检查事实。
Bartosz 2012年

4
抱歉,我在您的答案中添加了一些小修改,使其更准确,并投了赞成票。
dzida 2012年

4

我不同意谓词

if not orgs:

它应该是

if not orgs.count():

我遇到了同样的问题,结果集相当大(约有15万个结果)。运算符未在QuerySet中重载,因此实际上在进行检查之前将结果解压缩为列表。就我而言,执行时间减少了三个顺序。


6
__nonzero__已在QuerySet中重载。如果结果未缓存(永远不会在第一次使用queryset时使用),则__nonzero__的行为将遍历queryset中的所有元素。如果集合很大,这是非常糟糕的。
hedleyroos 2011年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.