Django上传文件默认权限为0600,因os.open()未显式指定mode而受系统umask(如0022)影响,导致Nginx用户(如www-data)无读取权限;需设置FILE_UPLOAD_PERMISSIONS=0o644,并确保MEDIA_ROOT及其父目录对Nginx用户具有执行(x)权限,且临时文件路径与MEDIA_ROOT同挂载点以避免move时权限丢失。

上传文件后 Nginx 返回 403,或者 open() 报 PermissionError,基本就是权限没设对——不是代码逻辑错,而是文件写入时的 umask 或 Django 配置没覆盖到实际磁盘行为。
为什么上传的文件默认是 0600 权限?
Django 默认用 os.open() 写文件,不显式指定 mode,系统就按当前进程 umask 裁剪权限。多数 Linux 服务器 umask 是 0022,结果文件权限就是 0600(即只有 owner 可读写),Nginx 工作进程(通常是 www-data 或 nginx 用户)根本打不开。
-
FILE_UPLOAD_PERMISSIONS必须显式设置为0o644(注意是八进制字面量,不是字符串或十进制) - 仅设这个还不够:如果上传走的是
TemporaryFileUploadHandler,临时文件也会继承同样权限,但最终 move 到MEDIA_ROOT时可能被重置——所以必须在 settings.py 里全局生效 - 别写成
FILE_UPLOAD_PERMISSIONS = "644"或644,Python 会报TypeError: an integer is required
上传大文件时权限丢失更隐蔽
当文件超过 FILE_UPLOAD_MAX_MEMORY_SIZE(默认 2.5MB),Django 会先写入临时目录(如 /tmp),再 move 到 MEDIA_ROOT。而 /tmp 下的文件权限由系统临时文件策略控制,FILE_UPLOAD_PERMISSIONS 对它无效。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 临时文件 move 后权限不一定保留,尤其跨文件系统时(比如
/tmp是 tmpfs,MEDIA_ROOT在 /var/www) - 解决方案:统一指定
FILE_UPLOAD_TEMP_DIR到和MEDIA_ROOT同一挂载点,并确保该目录对 Django 进程和 Nginx 进程都可读 - 加一行
os.chmod(real_path, 0o644)在保存后手动补权限,虽土但稳——前提是你的视图能拿到最终路径
生产环境 Nginx 访问 403 的真实原因
不是 Django 没给权限,而是 Nginx 根本没权限进入 MEDIA_ROOT 目录树。Linux 文件系统要求「所有父目录至少有 x 权限」才能 cd 进去。
立即学习“Python免费学习笔记(深入)”;
- 检查
MEDIA_ROOT所在路径每一级:比如/var/www/myproject/media,得确保/var、/var/www、/var/www/myproject都对 Nginx 用户(如 www-data)有x权限 - 常见错误:把
MEDIA_ROOT设成os.path.join(BASE_DIR, 'media'),而BASE_DIR是项目源码目录,其权限常为 0750(group 可读但无 x),导致 Nginx 卡在上层目录进不去 - 安全做法:把
MEDIA_ROOT移到独立路径(如/opt/myproject/media),并chown -R www-data:www-data /opt/myproject/media+chmod 0755 /opt/myproject
最易被忽略的一点:权限问题往往混合出现——你改了 FILE_UPLOAD_PERMISSIONS,却忘了 MEDIA_ROOT 父目录的执行位;你修好了目录权限,又因临时文件 move 失败导致新上传文件仍为 0600。排查时务必分层验证:先看文件自身权限,再看路径各级目录权限,最后确认 Nginx worker 进程用户身份是否匹配。

















