静态文件名里那串哈希是怎么来的?CSS 里引用的图片怎么跟着变?模板引用了没收集的文件会怎样?这篇跑一遍 collectstatic + ManifestStaticFilesStorage,把每个环节的产物都展示出来。
5 static files copied to '<实验目录>', 5 post-processed.
收集到的文件(原名 + 带哈希的副本):
css/base.7411b9041dad.css
css/base.css
css/site.8ba4b5966a42.css
css/site.css
img/bg.b04ebc27a009.png
img/bg.png
img/logo.79b11419e142.png
img/logo.png
js/app.5c4e6521f9b0.js
js/app.js
staticfiles.json
staticfiles.json 的键: ['paths', 'version', 'hash'] paths 映射:
css/base.css → css/base.7411b9041dad.css
css/site.css → css/site.8ba4b5966a42.css
img/bg.png → img/bg.b04ebc27a009.png
img/logo.png → img/logo.79b11419e142.png
js/app.js → js/app.5c4e6521f9b0.js模板里 {% static "css/site.css" %} 在生产环境(DEBUG=False)会查这张表,输出带哈希的 URL。
css/site.8ba4b5966a42.css 的内容:
@import url("base.7411b9041dad.css"); .logo{background:url("../img/logo.79b11419e142.png")} .bg{background:url("../img/bg.b04ebc27a009.png?v=1#x")} .ext{background:url('https://cdn.example.com/x.png')} .data{background:url(data:image/png;base64,AAAA)}这一步叫 post_process。因为要先算被引用文件的哈希,所以需要多趟处理(max_post_process_passes,本文没有测)。
app.js 内容的 md5[:12] = 5c4e6521f9b0 与 manifest 里的文件名一致: True 再运行一次(内容没变),映射不变: True 改了 app.js: js/app.5c4e6521f9b0.js → js/app.a2f0c2d96218.js 旧的哈希文件还留在目录里: True (不会自动删除,需要 --clear 或者定期清理)
有了哈希文件名,就可以给静态文件设很长的缓存时间(第 90 篇)。代价是旧版本文件累积;部署时要不要清理,取决于是否需要兼容还没刷新的旧页面。
ValueError: Missing staticfiles manifest entry for 'img/missing.png' <a href="/static/css/site.8ba4b5966a42.css">
常见触发场景:本地开发一直 DEBUG=True 没发现,上线后某个 {% static %} 引用了不存在的文件。CI 里可以对所有模板做一次 DEBUG=False 的渲染检查(本文没有做)。
非严格: img/late.png → /static/img/late.7f02e16a4a58.png 非严格: img/missing.png → ValueError: The file 'img/missing.png' could not be found with <proj.storage.NonStrict objec 严格: img/late.png → ValueError: Missing staticfiles manifest entry for 'img/late.png'
非严格模式是「宽容」而不是「万能」:文件真的不存在仍然报错。