Defer延迟的是指定字段的数据库读取,首次访问时才触发额外SQL查询;它不跳过字段存在,仅设为None,对大字段(如TextField)有效,但混用only()会覆盖、values后无效,且模板中隐式访问易引发N+1。

Defer在Django中到底延迟了什么?
defer() 只跳过指定字段的数据库读取,不跳过字段本身在Python对象上的存在——它会把被defer的字段设为None,直到你首次访问才触发一次额外的SQL查询(lazy load)。这意味着:
- 它对
TextField、JSONField、BinaryField这类可能很大的字段最有效 - 对
CharField或IntegerField等小字段,defer反而可能因多一次查询而变慢 -
defer()不影响filter()、order_by()等条件逻辑,但不能defer用于order_by()的字段(否则报FieldError)
怎么写才是安全有效的defer调用?
直接在QuerySet末尾链式调用defer(),传入字段名字符串列表:
- 用
.defer("content", "raw_data"),不要写成.defer("post__content")(跨表关系需用select_related()或prefetch_related()) - 若字段是外键关联的反向关系(如
author.posts.all()),defer()对反向管理器无效,得在Post.objects.filter(...).defer(...)里显式调用 - 多次
defer()会叠加,但only()会清空之前所有defer(),二者不要混用
示例:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
articles = Article.objects.filter(published=True).defer("body", "metadata")
此时articles[0].title可直接读,但articles[0].body第一次访问时会触发单独SELECT body, metadata FROM article WHERE id = ?
defer后访问字段时容易踩哪些坑?
- 在模板里写
{{ article.body }}会隐式触发懒加载,若循环渲染100条记录,就产生100次额外查询(N+1问题没解决)
-
isinstance(obj.body, str)或obj.body is None不会触发查询,但len(obj.body)、obj.body.split()会
- 使用
values()或values_list()后调用defer()无效(因为已转为字典/元组,不再有模型字段属性)
- 如果字段设置了
default或blank=True,defer()后该字段仍是None,不是默认值
比defer更稳的替代方案有哪些?
- 真要避免大字段IO,优先用
only()明确列出需要的字段(语义更清晰,不易漏)
- 对JSON类字段,考虑拆出独立表(如
ArticleMetadata),用select_related()按需关联
- 批量场景下,用
iterator(chunk_size=2000)配合defer()减少内存占用,但注意游标失效风险
- 如果只是展示列表页,干脆在序列化层(如Django REST Framework的
Serializer)里控制字段输出,数据库层不defer
{{ article.body }}会隐式触发懒加载,若循环渲染100条记录,就产生100次额外查询(N+1问题没解决) isinstance(obj.body, str)或obj.body is None不会触发查询,但len(obj.body)、obj.body.split()会 values()或values_list()后调用defer()无效(因为已转为字典/元组,不再有模型字段属性) default或blank=True,defer()后该字段仍是None,不是默认值 - 真要避免大字段IO,优先用
only()明确列出需要的字段(语义更清晰,不易漏) - 对JSON类字段,考虑拆出独立表(如
ArticleMetadata),用select_related()按需关联 - 批量场景下,用
iterator(chunk_size=2000)配合defer()减少内存占用,但注意游标失效风险 - 如果只是展示列表页,干脆在序列化层(如Django REST Framework的
Serializer)里控制字段输出,数据库层不defer
真正卡顿往往不在字段大小,而在没索引的WHERE条件或没限制的ORDER BY。先EXPLAIN查执行计划,再决定要不要defer。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










