Django 什么时候运行查询?

时间:2021-03-25 02:45:02

标签: python django

虽然我了解 Django 的 QuerySet 和延迟执行的高级思想,但我在 Django (3.1.2) 源代码中没有看到查询执行是如何触发的(即,数据库被命中)。例如,根据 Django documentationget() 查询似乎立即命中数据库。但是查看源代码(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_cacheresults_iter(),我认为必须调用它们才能与数据库后端交互?我的猜测是 Django 正在运行不同的进程/线程,而 PyCharm 只通过主线程?如果是这种情况,有人可以指出一些相关的代码吗?我自己似乎无法从 Google 找到任何帮助。谢谢!

编辑: 我通过查看代码知道 execute_sql() 可以触发数据库命中,因为它连接到 django.db.models.sql.compiler,后者执行 SQL 命令并将结果处理为 Python 对象,但我为什么从未涉足过这种方法?我想更好的问题是,_fetch_all() 什么时候被调用过?

1 个答案:

答案 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)

上面提到的文档还说明了何时准确评估查询集。

相关问题