【问题标题】:Checking for empty queryset in Django在 Django 中检查空查询集
【发布时间】:2010-11-26 03:23:36
【问题描述】:

检查查询是否返回任何结果的推荐习惯用法是什么?
示例:

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

我想有几种不同的检查方法,但我想知道有经验的 Django 用户会如何做。 文档中的大多数示例只是忽略了没有找到任何内容的情况...

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:
    if not orgs:
        # Do this...
    else:
        # Do that...
    

    【讨论】:

    • 这似乎也是文档中的首选,例如:docs.djangoproject.com/en/1.8/topics/http/shortcuts/#id7
    • @Wtower 如果过滤表达式没有命中任何记录,则您引用的代码必须让合约引发 404,或者如果有记录,则生成结果的list。那里的代码只会访问数据库一次。如果他们使用exist()count() 首先检查是否有返回记录,他们将访问数据库两次(一次检查,一次获取记录)。这是一个具体的情况。这并不意味着在一般情况中,了解查询是否会返回记录的首选方法是使用 do if queryset:...
    • @Louis 我引用的代码只是一个示例,它包含一行 if not my_objects: 以证明他们在文档中是这样做的。其他一切都完全无关紧要,所以我不明白你的意思。他们也可以提出一千个查询,但仍然完全无关紧要,因为这不是这个答案的重点,我明确表示我同意。
    • @Wtower 这只是解释get_object_or_404的工作原理,不是 检查查询集中是否存在任何元素的首选方法。在查询集上执行 list() 将获取查询集上的每个对象,如果返回很多行,这将比查询两次更糟糕。
    • 有关更详细的答案,请查看以下@leonid-shvechikov 的答案:如果不评估 qs,使用.exists() 会更有效。
    【解决方案2】:

    从 1.2 版本开始,Django 有了 QuerySet。exists() 方法是最高效的:

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

    但是,如果您要评估 QuerySet 还是最好使用:

    if orgs:
       ...
    

    欲了解更多信息read QuerySet.exists() documentation

    【讨论】:

    • .exists() 仅适用于 .filter(),有什么适用于 .get() 的吗?
    • .get 不返回查询集。它返回一个对象。所以谷歌了
    • 只有当你有一个大的 QuerySet 时,它才会明显更有​​效率:docs.djangoproject.com/en/2.1/ref/models/querysets/#exists
    • 这要快得多!
    【解决方案3】:

    如果你有大量的对象,这可以(有时)更快:

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

    在我正在处理一个大型数据库的项目中,not orgs 是 400+ 毫秒,orgs.count() 是 250 毫秒。在我最常见的用例(有结果的用例)中,这种技术通常会将其缩短到 20 毫秒以下。 (我发现的一个案例是 6 个。)

    当然,可能会更长,这取决于数据库要查找多远才能找到结果。或者甚至更快,如果它很快找到一个; YMMV。

    编辑:如果没有找到结果,这通常比orgs.count() 慢,特别是如果您过滤的条件是罕见的;因此,它在需要确保视图存在或抛出 Http404 的视图函数中特别有用。 (人们希望,人们要求的 URL 经常存在。)

    【讨论】:

      【解决方案4】:

      检查查询集是否为空:

      if orgs.exists():
          # Do something
      

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

      if orgs.first():
          # Do something
      

      【讨论】:

      • if orgs.exists()answer 覆盖,该answer 在此之前大约 5 年提供。这个答案带来的唯一也许新的东西是if orgs.first()。 (即使这也值得商榷:它与大约 5 年前的 orgs[0] suggested 是否也有很大不同?)您应该提出答案的那一部分:什么时候想要这样做而不是 之前提出的其他解决方案?
      【解决方案5】:

      最有效的方法(在 django 1.2 之前)是这样的:

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

      【讨论】:

      • .exists() 似乎效率更高
      • 除了 .exists() 是在我发表评论几个月后添加的,而 Django 1.2(包含该 API)在大约 8 个月后发布。但感谢您投反对票并且不费心检查事实。
      • 对不起,我对您的答案进行了小修改,以使其更准确并投赞成票。
      【解决方案6】:

      我不同意谓词

      if not orgs:
      

      应该是

      if not orgs.count():
      

      我在相当大的结果集(约 150k 个结果)中遇到了同样的问题。该运算符在 QuerySet 中没有重载,因此在进行检查之前,实际上将结果解包为列表。在我的例子中,执行时间减少了三个订单。

      【讨论】:

      • __nonzero__ 已经在 QuerySet 中重载。如果结果没有被缓存(它永远不会在第一次使用查询集时),则 __nonzero__ 的行为是遍历查询集中的所有元素。如果集合很大,这是非常糟糕的。
      【解决方案7】:

      你也可以这样用:

      if(not(orgs)): #if orgs is empty else: #if orgs is not empty

      【讨论】:

        猜你喜欢
        • 2012-04-14
        • 2013-06-30
        • 1970-01-01
        • 2020-08-27
        • 1970-01-01
        • 2013-04-22
        • 2018-10-05
        • 2018-12-01
        • 1970-01-01
        相关资源
        最近更新 更多