我有一个Django模型,可以将文件名保存为" uuid4()。pdf"。其中uuid4为每个创建的实例生成一个随机uuid。此文件名也存储在具有相同名称的amazon s3服务器上。
我正在尝试为我上传到亚马逊s3的文件名添加自定义处置,这是因为我想在每次下载文件而不是uuid文件时看到自定义名称。同时,我希望文件以uuid文件名存储在s3上。
所以,我正在使用django-storages和python 2.7。我尝试在这样的设置中添加content_disposition:
AWS_CONTENT_DISPOSITION = 'core.utils.s3.get_file_name'
其中get_file_name()返回文件名。
我也尝试将其添加到设置中:
AWS_HEADERS = {
'Content-Disposition': 'attachments; filename="%s"'% get_file_name(),
}
没有运气!
你们中的任何人都知道要实现这一点。
答案 0 :(得分:1)
我猜您正在使用 django-storages 中的 S3BotoStorage ,因此在将文件上传到S3时,请覆盖模型的save()方法,并设置标题那里。
我在下面给出一个例子:
<cftransaction>
答案 1 :(得分:0)
django-storages的S3Boto3Storage当前版本支持AWS_S3_OBJECT_PARAMETERS
全局设置变量,该变量也允许修改ContentDisposition
。但是问题在于,它按原样应用于所有上载到s3的对象,而且会影响使用该存储的所有模型,这可能不是预期的结果。
以下hack对我有用。
from storages.backends.s3boto3 import S3Boto3Storage
class DownloadableS3Boto3Storage(S3Boto3Storage):
def _save_content(self, obj, content, parameters):
"""
The method is called by the storage for every file being uploaded to S3.
Below we take care of setting proper ContentDisposition header for
the file.
"""
filename = obj.key.split('/')[-1]
parameters.update({'ContentDisposition': f'attachment; filename="{filename}"'})
return super()._save_content(obj, content, parameters)
这里,我们重写了存储对象的本机保存方法,并确保在每个文件上设置了正确的内容处置。 当然,您需要将此存储提供给您正在处理的字段:
my_file_filed = models.FileField(upload_to='mypath', storage=DownloadableS3Boto3Storage())
答案 2 :(得分:0)
万一有人发现它,就像我一样:SO中提到的所有解决方案都无法在Django 3.0中为我工作。
S3Boto3Storage
的文档字符串建议覆盖S3Boto3Storage.get_object_parameters
,但是此方法仅接收name
的已上传文件,目前已被upload_to
更改,并且可能与原始的。
以下是有效的方法:
class S3Boto3CustomStorage(S3Boto3Storage):
"""Override some upload parameters, such as ContentDisposition header."""
def _get_write_parameters(self, name, content):
"""Set ContentDisposition header using original file name.
While docstring recomments overriding `get_object_parameters` for this purpose,
`get_object_parameters` only gets a `name` which is not the original file name,
but the result of `upload_to`.
"""
params = super()._get_write_parameters(name, content)
original_name = getattr(content, 'name', None)
if original_name and name != original_name:
content_disposition = f'attachment; filename="{original_name}"'
params['ContentDisposition'] = content_disposition
return params
,然后在文件字段中使用此存储空间,例如:
file_field = models.FileField(
upload_to=some_func,
storage=S3Boto3CustomStorage(),
)
无论您想出什么解决方案,都请勿直接更改file_field.storage.object_parameters
(例如,在类似问题中曾建议在模型的save()
中更改),因为这会更改{ {1}}标头,用于使用相同存储的任何字段的后续文件上传。这可能不是您想要的。