必须禁用FILE_UPLOAD_MAX_MEMORY_SIZE并改用流式上传:前端分块、后端用boto3/minio直传对象存储,绕过Django文件处理链路,结合Redis管理分片、环境变量配置存储后端及权限校验。

大模型文件上传卡在内存里,Django默认FileField扛不住
Django的FileField和ImageField底层走的是Python的file.read(),上传100MB+文件时,整个请求体先被读进内存再写入磁盘或存储后端——这直接触发MemoryError或被WSGI服务器(如Gunicorn)杀掉进程。
根本原因不是Django慢,而是它默认不支持“流式上传”:没等客户端传完,服务端就急着把全部内容load进内存了。
- 必须禁用
FILE_UPLOAD_MAX_MEMORY_SIZE(设为0),强制绕过内存缓冲 - 确保WSGI服务器(如Nginx)配置了
client_max_body_size,且大于目标文件上限 - 前端要用
fetch或XMLHttpRequest分块上传,避免表单直接submit
MinIO/S3上传不能靠django-storages硬配,得自己接管upload handler
django-storages对minio或boto3的封装,只管“保存到哪里”,不管“怎么传上去”。它依然依赖Django的UploadedFile对象,而这个对象默认是InMemoryUploadedFile或TemporaryUploadedFile——前者吃内存,后者写临时磁盘再读,一样卡。
真正要走对象存储直传,得跳过Django的文件处理链路,在视图层拿到原始request.body流,用boto3.client.upload_fileobj()或minio.Minio.put_object()直接推。
立即学习“Python免费学习笔记(深入)”;
- 视图里别碰
request.FILES,改用request.body+Content-Length头校验大小 - 用
boto3.client('s3', config=Config(signature_version='s3v4'))确保兼容MinIO - MinIO需显式传
secure=False,否则HTTPS握手失败 - 上传前生成唯一
object_name(比如f"{uuid4()}/{original_name}"),避免覆盖
前端分块上传没配好,后端收不到完整流
浏览器原生fetch发大文件时,如果没手动分块,服务端收到的就是一个超长request.body,容易超时或被中间件截断。MinIO/S3本身支持multipart upload,但Django不会自动帮你拆——得前端切、后端合。
推荐用uppy.io或手写File.slice(),配合后端提供/api/upload/init(返回upload_id)和/api/upload/part(接收每个Blob)。
- 每块大小建议
5 * 1024 * 1024(5MB),符合S3最小分块要求 - 后端保存
upload_id和已上传part列表到缓存(如Redis),别放DB里拖慢流程 - 最后调用
boto3.client.complete_multipart_upload()或minio.complete_multipart_upload()拼合 - 别忘了清理失败上传:
boto3.client.abort_multipart_upload()
本地开发用MinIO,但Django settings里写死了endpoint就跑不起来
MinIO在本地用http://localhost:9000,上生产可能换https://s3.us-east-1.amazonaws.com,如果在settings.py里硬编码MINIO_ENDPOINT,环境一换就得改代码,CI/CD会炸。
正确做法是用环境变量驱动,且对MinIO和S3做适配层封装,而不是让业务代码到处判断if MINIO_ENABLED。
- 用
os.getenv('STORAGE_BACKEND', 'local')控制后端类型 - MinIO配置必须带
region='us-east-1'(即使不用),否则boto3报InvalidRegionError - S3的
AWS_S3_REGION_NAME和MinIO的MINIO_REGION要一致,不然签名失败 - 本地MinIO账号密码默认是
minioadmin/minioadmin,别漏配MINIO_ACCESS_KEY和MINIO_SECRET_KEY
最麻烦的其实是权限链路:Django用户 → 视图鉴权 → 对象存储Policy → CDN缓存头。每层漏一个,文件就403或不缓存。这些细节没法靠配置自动补全,得逐层测。


















