必须严格分离static与media文件:static是版本可控的代码资产,media是用户可变内容;混放会导致安全风险、部署混乱和功能失效,需通过nginx分别配置路径与权限,并统一使用{{ object.file.url }}动态生成media url。

因为它们的来源、用途、安全要求和生命周期完全不同,混在一起会直接导致安全隐患、部署混乱或功能失效。
静态文件(Static)是代码的一部分,媒体文件(Media)是用户内容
Static 文件如 base.css、jquery.min.js、项目 logo 图片,随代码一起提交 Git,版本可控,上线后极少变动;Media 文件如用户头像 avatar_123.jpg、文章封面图,由 FileField 或 ImageField 生成,存在数据库记录关联,且随时可被上传、覆盖、删除。
如果把用户上传的文件也放进 static/ 目录:
- Django 的
collectstatic命令会把它一并复制进STATIC_ROOT,下次部署可能意外覆盖或丢失用户数据 - Git 提交时容易误提交大量二进制文件,污染仓库、拖慢 clone 速度
- 无法做独立的备份策略——你不会想每次备份代码时都打包几 GB 用户图片
安全边界必须隔离:不能让用户控制 Static 路径
Django 开发服务器默认允许通过 URL 访问 static/ 下任意路径,比如 /static/../manage.py —— 但这是受控的,因为 static 内容由开发者完全掌控。而 Media 文件来自用户输入,若混放,攻击者可能上传恶意文件(如 shell.php),再通过构造 URL 直接执行。
分离后,生产环境通常用 Nginx 分别配置:
location /static/ {
alias /var/www/myproject/static/;
}
location /media/ {
alias /var/www/myproject/media/;
# 可额外加限制:只允许图片、PDF 等白名单类型
if ($request_filename ~ \.(php|exe|sh)$) { return 403; }
}
这种细粒度控制在混放时根本做不到。
开发与生产服务方式天然不同
开发阶段,Django 用 django.views.static.serve 同时服务 STATIC_ROOT 和 MEDIA_ROOT,但仅限 DEBUG=True;生产环境必须交给 Nginx/Apache 直接读取文件系统——而 collectstatic 只处理 Static,从不碰 Media。
关键区别:
-
STATIC_ROOT是构建产物目录,由命令生成,**绝不应写入** -
MEDIA_ROOT是运行时可写目录,需确保 Web 进程有写权限,且定期备份 -
STATICFILES_DIRS可以是多个路径(如themes/default/static),但MEDIA_ROOT必须唯一且明确
最常被忽略的一点:很多人在模板里对 Media 文件硬编码 /media/xxx,却忘了 MEDIA_URL 可能是 /uploads/ 或带域名前缀(如 https://cdn.example.com/media/)。始终用 {{ object.file.url }} 或 {{ MEDIA_URL }}{{ filename }},别手写路径。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











