Django 究竟什么时候运行查询?



虽然我理解 Django 的 QuerySet 和延迟执行的高级思想,但我在 Django (3.1.2) 源代码中没有看到查询执行是如何触发的(即数据库被命中)。例如,根据 Django 文档,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发送到数据库引擎的位置(即包含被解析为 SQL 的实际Query对象的self._query)并以某种方式将结果缓存在_result_cache中。事实上,当我尝试单步执行代码时,在某些时候,self._result_cache"神奇地"填充了查询结果。我从未涉足任何与SQL相关的代码,例如django.db.models.sql.compiler中的results_iter()execute_sql(),我认为必须调用这些代码才能与数据库后端进行交互?我的猜测是 Django 正在运行不同的进程/线程,而 PyCharm 只通过主线程?如果是这种情况,有人可以指出一些相关的代码吗?我自己似乎无法从谷歌那里找到任何帮助。谢谢!

编辑: 我从代码中知道_fetch_all()可以触发数据库命中,因为它连接到ModelIterable,执行SQL命令并将结果处理成Python对象,但是为什么我从来没有进入过这种方法?我想更好的问题是,_fetch_all()什么时候打电话?

从您添加的代码中,请参阅以下行:

num = len(clone)

可以看到我们正在对查询集调用len。根据何时评估 QuerySets - Django 文档:

伦().当你对QuerySet调用len()时,会对其进行计算。如您所料,这将返回结果列表的长度。

进一步查看源代码 - GitHublen会调用_fetch_all(),因为您正确地假设结果来自哪里:

def __len__(self):
self._fetch_all()
return len(self._result_cache)

上面提到的文档还记录了何时准确计算查询集。

最新更新