在 Django 查询集上使用 iterator()

Posted

技术标签:

【中文标题】在 Django 查询集上使用 iterator()【英文标题】:usage of iterator() on django queryset 【发布时间】:2011-06-30 20:11:05 【问题描述】:

我最近遇到了一些奇怪的行为,需要检查我的理解。

我在模型中使用了一个简单的过滤器,然后对结果进行迭代。

例如

allbooks = Book.objects.filter(author='A.A. Milne')

for book in allbooks:
   do_something(book)

奇怪的是,它只返回了部分书籍列表。

但是,当使用相同的代码并使用 iterator() 时,这似乎工作得很好。

for book in allbooks.iterator():
    do_something(book)

知道为什么吗?

附言我确实浏览了 Django 文档,但看不到查询集将如何被缓存在其他任何地方......

iterator() 评估 QuerySet(通过执行查询)并返回结果的迭代器。 QuerySet 通常会在内部缓存其结果,以便重复评估不会导致额外的查询; iterator() 将直接读取结果,而不在 QuerySet 级别进行任何缓存。对于返回大量对象的 QuerySet,这通常会带来更好的性能和显着减少的内存

请注意,在已评估的 QuerySet 上使用 iterator() 将强制它再次评估,重复查询。

【问题讨论】:

我刚刚注意到的另一件奇怪的事情。不使用 iterator() 时 - 它只返回 100 个对象。这似乎与前 100 个对象由 'iter' 自动缓存的事实相匹配,但我仍然想知道为什么循环只是在那里结束并且不继续迭代与过滤器匹配的所有对象。 【参考方案1】:

奇怪的是,它只返回了一部分 书籍清单。

这不是查询集必须如何工作的。遍历查询集应该为您提供数据库返回的每条记录。调试你的代码。你会发现错误,否则再次调试。

检查 REPL 很容易。运行manage.py shell

from app.models import Model
for o in Model.objects.filter(fieldname="foo"): print o

#Let's see DB query
from django.db import connection
print(connection.queries)

【讨论】:

谢谢,完全相同的代码在同一个数据库中没有 .iterator() 返回 100 条记录。有了它 - 129。另外,如果我这样做:len(allbooks) for book in allbooks: 返回 129 你是对的。 do_something(book) 中的某些内容正在遍历相同的所有书籍... doh! 太棒了!我一直试图弄清楚如何在没有成功的情况下访问查询集中的值,直到 10 年前我偶然发现了这个答案!谢谢!【参考方案2】:

QuerySet 通常会在内部缓存其结果,以便重复计算不会导致额外的查询。相比之下,iterator() 将直接读取结果,而不在QuerySet 级别进行任何缓存。

https://docs.djangoproject.com/en/dev/ref/models/querysets/

【讨论】:

@LuFFy 在 slugrelatefield 中,有一个参数 "queryset" ,有没有办法可以使用迭代器?

以上是关于在 Django 查询集上使用 iterator()的主要内容,如果未能解决你的问题,请参考以下文章

查询集上的 Django 总和

如何使用 django 和 htmx 对查询集进行排序?

如何禁用 Django 查询缓存?

查看 Django 查询集删除的 SQL 查询

Django学习之model进阶

数据集上的慢联合