在python中为文件名(amazon S3)添加动态内容处理

时间:2017-04-04 13:17:54

标签: python django amazon-web-services amazon-s3 django-storage

我有一个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(),

 }

没有运气!

你们中的任何人都知道要实现这一点。

3 个答案:

答案 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}}标头,用于使用相同存储的任何字段的后续文件上传。这可能不是您想要的。