使用 Django QuerySets 时使用列表推导而不是 for 循环

Posted

技术标签:

【中文标题】使用 Django QuerySets 时使用列表推导而不是 for 循环【英文标题】:Using list comprehension instead of for loop when working with Django QuerySets 【发布时间】:2011-10-06 13:28:40 【问题描述】:

我正在尝试调整一个在速度部门遇到问题的应用程序。因此,我已开始尽可能将所有 for 循环语句转换为列表推导式。

目前,我正在研究一个需要遍历 Django 查询集字典的函数。旧代码使用 for-loop 语句来迭代它并且它工作正常。我使用列表理解的代码返回 django 查询集而不是我的模型对象。

代码如下:

def get_children(parent):
  # The following works
  children = []
  for value in get_data_map(parent).itervalues():
    children += list(value)
  # This part doesn't work as intended.
  booms = [value for value in get_data_map(parent).itervalues() if value]
  import pdb
  pdb.set_trace()


(Pdb) type(children[0])
<class 'site.myapp.models.Children'>

(Pdb) type(booms[0])
<class 'django.db.models.query.QuerySet'>

注意 get_data_map 返回一个字典,其值为&lt;class 'django.db.models.query.QuerySet'&gt;

这部分代码是应用程序中最耗时的部分之一。如果我在列表推导上进行这项工作,应用程序速度有望提高两倍。

知道如何加快这部分代码的速度吗?

【问题讨论】:

是什么让您认为列表解析比执行常规 for ... in ... 循环更快? 我对生成器、列表推导、for 循环和 map 做了一个简单的测试,列表推导比 for .. 循环快了将近两倍。 【参考方案1】:

同意很难准确判断到底发生了什么,但是使用 django 调试工具栏可以大大简化调试 django 速度问题:

https://github.com/django-debug-toolbar/django-debug-toolbar

如果问题是 db hits 太多,请查看工具栏上的“SQL 查询”选项卡,它会非常清楚地显示出来。

【讨论】:

【参考方案2】:

您的问题不是 for 循环与列表推导(最好是生成器)。您的问题是对数据库的查询太多

由于您尝试获取一个列表,因此您应该尝试从一个查询中获取它。如果您解释了典型 QuerySet 中的内容,我们可以向您展示如何最好地合并它们。也许在 Q 对象上使用 OR 合并。或者可能建立一组整数并将其提供给__in= 过滤器。

【讨论】:

假设这是不可解决的,并且 OP 实际上并没有使用整个列表, itertools.chain 会使其更快,因为不是每个查询集都会导致查询(因为懒惰评估)。 是的,考虑到这么少的信息,真的很难说该怎么做。但是,我发现查询开销比 Django 中的循环开销要大得多。【参考方案3】:

您的解决方案不起作用,因为您正在创建查询集列表。每个值都是一个查询集,您无处可加入它们。比较:

a = [1,2,3]
b = [x for x in a if x ]

你会期望 b 也是一个整数列表,对吧?您获得了查询集列表(比父列表更好),但您仍然需要加入它们。您可以使用 itertools.chain 执行此操作:

http://docs.python.org/library/itertools.html#itertools.chain

foos = itertools.chain(booms)

foos 应该是你想要的。

【讨论】:

以上是关于使用 Django QuerySets 时使用列表推导而不是 for 循环的主要内容,如果未能解决你的问题,请参考以下文章

django不返回QuerySets的API

如何使用 QuerySets 和 MySql“全文搜索”在多个字段中进行 Django 搜索?

如何使用 Django Querysets 和 Q() 与相同模型类型的对象进行比较?

有没有办法在 Django Querysets 中组合注释和过滤聚合?

python Django:QuerySets

如何测试 Django QuerySets 是不是相等?