cached.Loader未生效主因是配置错误:必须将其严格嵌套为['django.template.loaders.cached.Loader', ['loader1', 'loader2']]结构,否则仅包装首个loader;其缓存键依赖模板路径与st_mtime,mtime不变或未重启进程将导致缓存不更新。

模板渲染慢,不是数据库或视图拖后腿,大概率是每次都要重新读文件、解析、编译——cached.Loader 就是专治这个的,但它默认不生效,配错就等于没开。
为什么 cached.Loader 没生效?常见配置陷阱
它不会自动启用,必须手动嵌套进 TEMPLATES 的 OPTIONS['loaders'] 里,且结构必须严格:
- 错误写法:
['django.template.loaders.cached.Loader', 'django.template.loaders.filesystem.Loader']—— 这会让cached.Loader只包装第一个 loader,后面全绕过 - 正确写法:
['django.template.loaders.cached.Loader', ['django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader']]—— 第二个参数必须是 list,cached.Loader才会包裹整个 loader 链 - 开发时改了模板却没更新?不是缓存后端问题,而是
cached.Loader把编译后的Template对象存在 Python 进程内存里,st_mtime检查失效(比如 NFS 或符号链接)或没重启 dev server,缓存就卡死
cached.Loader 缓存键怎么算?别指望清空 Redis 就能刷新
它的缓存不走 CACHES['default'],完全独立于你配的 Redis/Memcached,只用进程内字典或 lru_cache 存编译结果:
- 缓存键 = 模板路径字符串(如
'blog/post_detail.html') +os.stat().st_mtime - 清空
cache.delete_pattern('template.*')完全无效,因为根本没用那个 cache backend - 改了模板但
st_mtime没变(例如 Git checkout、Docker volume 挂载、NFS 时间不同步),缓存就永远不更新
什么情况下不该用 cached.Loader?收益远小于代价
它不是万能加速器,用错反而添乱:
立即学习“Python免费学习笔记(深入)”;
- 模板总数少于 50 个、QPS 很低的小项目,首字节延迟可能反增,收益几乎测不出来
- 动态拼模板名,比如
get_template(f'emails/{lang}/welcome.html'),lang组合一多,缓存条目爆炸,且无法预热 - 用
select_template()做多层 fallback(设备 + 语言 + 主题),命中率骤降,大部分请求仍要遍历 loader 链 - 自定义 loader 没实现
get_template_sources()或返回的mtime总是 0,cached.Loader会直接退化成直通模式
真正起效的关键,是确认 cached.Loader 正确包裹了所有实际用到的 loader,并接受它“首次加载慢、后续快”的特性;别试图用外部缓存工具去清理它,重启进程才是开发期唯一可靠的刷新方式。


















