虽然我了解 Django 的 QuerySet 和延迟执行的高级思想,但我在 Django (3.1.2) 源代码中没有看到查询执行是如何触发的(即,数据库被命中)。例如,根据 Django documentation,get()
查询似乎立即命中数据库。但是查看源代码(django.db.models.query
):
def get(self, *args, **kwargs):
"""
Perform the query and return a single object matching the given
keyword arguments.
"""
clone = self._chain() if self.query.combinator else self.filter(*args, **kwargs)
if self.query.can_filter() and not self.query.distinct_fields:
clone = clone.order_by()
limit = None
if not clone.query.select_for_update or connections[clone.db].features.supports_select_for_update_with_limit:
limit = MAX_GET_RESULTS
clone.query.set_limits(high=limit)
num = len(clone)
if num == 1:
return clone._result_cache[0]
if not num:
raise self.model.DoesNotExist(
"%s matching query does not exist." %
self.model._meta.object_name
)
raise self.model.MultipleObjectsReturned(
'get() returned more than one %s -- it returned %s!' % (
self.model._meta.object_name,
num if not limit or num < limit else 'more than %s' % (limit - 1),
)
)
我没有看到 clone
(它是一个 QuerySet
对象)向数据库引擎发送它的 query
(即包含实际 {{ 1}} 对象被解析为 SQL)并以某种方式将结果缓存在 self._query
中。事实上,当我尝试单步执行代码时,在某些时候,Query
“神奇地”填充了查询结果。我从未涉足任何与 SQL 相关的代码,例如 _result_cache
中的 self._result_cache
或 results_iter()
,我认为必须调用它们才能与数据库后端交互?我的猜测是 Django 正在运行不同的进程/线程,而 PyCharm 只通过主线程?如果是这种情况,有人可以指出一些相关的代码吗?我自己似乎无法从 Google 找到任何帮助。谢谢!
编辑:
我通过查看代码知道 execute_sql()
可以触发数据库命中,因为它连接到 django.db.models.sql.compiler
,后者执行 SQL 命令并将结果处理为 Python 对象,但我为什么从未涉足过这种方法?我想更好的问题是,_fetch_all()
什么时候被调用过?
答案 0 :(得分:1)
从您添加的代码中,看到这一行:
num = len(clone)
可以看到我们在查询集上调用 len
。根据{{3}}:
len()。当您对其调用 len() 时,会评估 QuerySet。正如您所料,这将返回结果列表的长度。
进一步查看 When QuerySets are evaluated - Django docs len
会调用 _fetch_all()
,正如您正确假设的那样是结果的来源:
def __len__(self):
self._fetch_all()
return len(self._result_cache)
上面提到的文档还说明了何时准确评估查询集。