You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django QuerySet执行get的评估范围与重复调用查库规则

核心结论

在Django ORM中对QuerySet调用get()方法时,不会预先评估整个QuerySet集合拉取全部匹配数据,每次get()调用都会基于原有QuerySet的过滤条件追加新的查询规则,生成独立SQL访问数据库。给出的示例中,两次get()调用都会各自触发一次数据库查询,既不会拉取filter(a="something")匹配的全部5条数据,也不会复用彼此的查询结果。

具体机制说明
  • QuerySet本身是惰性对象:执行qs = Model.objects.filter(a="something")时不会触发任何数据库操作,只是在内存中生成了一个存储查询条件的QuerySet实例,没有做任何求值动作。
  • get()会合并查询条件直接查库:在已有QuerySet上调用get(b=xxx)时,Django不会先执行原filter的SQL把所有匹配结果拉到内存再做筛选,而是直接将两层过滤条件合并为a="something" AND b="xxx",生成单条SQL查询。为了快速校验结果是否恰好为1条,ORM会自动给SQL加上LIMIT 21:只要查询返回超过1条结果就直接抛出MultipleObjectsReturned异常,返回0条则抛出DoesNotExist异常,全程不会加载多余数据。
  • get()不触发QuerySet缓存逻辑:QuerySet的结果缓存仅在全量求值场景下生效,比如迭代整个QuerySet、调用list(qs)、len(qs)、做全量切片时,才会把所有匹配结果拉到内存缓存。而get()属于单实例查询方法,既不会读取QuerySet的已有缓存,也不会把查询结果写入QuerySet缓存,无论之前有没有对qs做过全量求值,每次调用get()都会重新生成SQL访问数据库。
示例对应的实际SQL

示例代码中,两次get()调用执行的是完全独立的两条SQL,不会出现先拉取5条a匹配数据的情况:
第一次调用obj = qs.get(b='something_else')执行的SQL大致为:

SELECT * FROM test_model WHERE a = 'something' AND b = 'something_else' LIMIT 21;

第二次调用obj2 = qs.get(b='something_else_2')执行的SQL大致为:

SELECT * FROM test_model WHERE a = 'something' AND b = 'something_else_2' LIMIT 21;
常见误区提醒

不要误以为链式调用filter后接get会先把filter的结果全拉到内存筛选,ORM会在SQL层合并所有查询条件,不会做无意义的内存数据拉取;也不要误以为第一次操作QuerySet后所有后续调用都会走缓存,get()、filter()这类生成新查询、或者返回单实例的方法,默认都不会复用QuerySet的全量结果缓存。

内容的提问来源于stack exchange,提问作者coderelliot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 12:21:18