Django中如何覆盖存储在MEDIA_ROOT外的ImageField上传文件?
报错根因
两个错误的核心都是自定义存储类未正确配置存储根路径:
SuspiciousFileOperation报错:手动拼接的文件路径不在当前存储类声明的根路径范围内,Django为了防范路径穿越攻击直接拦截了操作- 文件存储位置错误:自定义存储类实例化时未传入指定的
location参数,默认使用了settings.MEDIA_ROOT作为存储根路径,导致文件存到了项目本地目录而非目标外部目录
正确实现方案
1. 重写自定义存储类
不需要额外新增MEDIA_TRACK配置,直接在自定义存储类内部调用自身方法获取路径,避免手动拼接路径触发安全校验:
# storages.py from django.core.files.storage import FileSystemStorage import os class OverwriteFileSystemStorage(FileSystemStorage): def get_available_name(self, name, max_length=None): # 调用存储类自身的exists和path方法,自动适配配置的根路径 if self.exists(name): os.remove(self.path(name)) return name
2. 实例化存储类时指定外部路径
直接传入你要使用的外部存储目录,不需要修改全局MEDIA_ROOT配置:
# storages.py 追加内容 remote_overwrite_storage = OverwriteFileSystemStorage( location='/Users/some_dir/Documents/dev/mediatest/', base_url='/Users/some_dir/Documents/dev/mediatest/' ) # 原有upload_to函数保持不变即可 def upload_to(instance, filename): dir_name = 'volume-'+str(instance.pk) filename = 'image_1'+filename[-4:] return '%s/%s' % (dir_name, filename)
3. 模型字段绑定存储实例
# models.py from .storages import upload_to, remote_overwrite_storage class Newsletter(models.Model): image_1 = models.ImageField(upload_to=upload_to, storage=remote_overwrite_storage)
额外注意
如果你的模型实例是首次创建还未写入数据库时,instance.pk会为空,此时upload_to生成的路径会出现volume-None的目录,如果要规避这个问题可以配合post_save信号处理首次上传的文件重命名逻辑。
内容的提问来源于stack exchange,提问作者Radial
相关产品推荐
相关产品推荐

