模板渲染变慢主因是loader反复扫描模板路径,启用cached.Loader可固化“模板名→文件路径”映射跳过遍历;需严格嵌套配置、重启进程刷新缓存,且不适用于模板少、动态拼接或fallback复杂等场景。

为什么模板渲染变慢?先看是不是 loader 在反复扫描
模板渲染慢,八成不是逻辑问题,而是每次请求都重新读文件、解析、编译。Django 默认的 filesystem.Loader 和 app_directories.Loader 在 DEBUG=False 时虽缓存编译结果,但“找模板”这步仍要逐个 app 目录遍历——尤其当项目有几十个 app 或大量 {% include %} 时,开销明显。
启用 cached.Loader 必须嵌套配置,否则等于没开
它不单独干活,只是给其他 loader 加一层缓存壳。常见错误是把它和原始 loader 并列写:
['django.template.loaders.cached.Loader', 'django.template.loaders.filesystem.Loader']
这会让 cached.Loader 只包装第一个 loader,后面全绕过。正确写法必须是:
- 外层 list 第一个元素是
cached.Loader类名 - 第二个元素是包含所有实际 loader 的内层 list
- 自定义 loader(比如从 DB 读模板)也得塞进这个内层 list
配置示例:
立即学习“Python免费学习笔记(深入)”;
[('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
])]
cached.Loader 缓存存在进程内存里,重启才是唯一可靠刷新方式
它的缓存键 = 模板路径字符串 + os.stat().st_mtime,和你配的 CACHES 完全无关。这意味着:
-
cache.delete_pattern('template.*')完全无效 - 改了模板但没看到更新?不是 Redis 没清,是进程内存里的缓存没刷新
- 用 NFS 或符号链接挂载模板目录时,
st_mtime可能不准,缓存可能长期卡死 - 开发中唯一可靠办法:重启
runserver;生产用 gunicorn 则需 reload worker 进程
哪些场景下 cached.Loader 反而有害?
它只加速重复加载,不解决首次慢的问题。以下情况收益低甚至拖慢:
- 模板总数少于 50 个:Python 解析本身开销小,加 wrapper 白费 CPU
- 动态拼模板名,如
get_template(f'emails/{lang}/{region}/body.html'):组合爆炸导致缓存条目剧增,命中率趋近于 0 - 大量用
select_template()做 fallback(设备 + 语言 + 主题三重判断):缓存无法预热,每次仍要遍历候选列表 - CI/CD 部署挂载 NFS 模板目录:
st_mtime不稳定,缓存可能误刷新或永不刷新
真正起效的前提,是确认它包裹了所有实际用到的 loader,并接受“首次加载慢、后续快”的特性——别指望它自动适配所有动态路径或小项目场景。


















