【问题标题】:Add Dynamic Content Disposition for file names(amazon S3) in python在 python 中为文件名(amazon S3)添加动态内容处置
【发布时间】:2017-08-29 17:20:53
【问题描述】:

我有一个将文件名保存为“uuid4().pdf”的 Django 模型。其中 uuid4 为每个创建的实例生成一个随机 uuid。此文件名也存储在同名的 amazon s3 服务器上。

我正在尝试为我上传到 amazon s3 的文件名添加自定义配置,这是因为我希望在下载文件而不是 uuid 文件时看到自定义名称。同时,我希望文件以 uuid 文件名存储在 s3 上。

所以,我在 python 2.7 中使用django-storages。我曾尝试在这样的设置中添加 content_disposition:

AWS_CONTENT_DISPOSITION = 'core.utils.s3.get_file_name'

其中 get_file_name() 返回文件名。

我也尝试将其添加到设置中:

AWS_HEADERS = {
'Content-Disposition': 'attachments; filename="%s"'% get_file_name(),

 }

运气不好!

你们有认识的人来实现这个吗?

【问题讨论】:

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


    【解决方案1】:

    我猜你正在使用 django-storages 中的 S3BotoStorage,所以在将文件上传到 S3 时,覆盖模型的 save() 方法,并设置标题在那里。

    下面我举个例子:

    class ModelName(models.Model):
        sthree = S3BotoStorage()
        def file_name(self,filename):
            ext = filename.split('.')[-1]
            name = "%s/%s.%s" % ("downloads", uuid.uuid4(), ext)
            return name
        upload_file = models.FileField(upload_to=file_name,storage = sthree)
        def save(self):
            self.upload_file.storage.headers = {'Content-Disposition': 'attachments; filename="%s"' %self.upload_file.name}
            super(ModelName, self).save()
    

    【讨论】:

    • 只有在您使用S3BotoStorage 时,才可以将其调整为有条件地设置标题。有了它,您可以轻松创建测试,而无需关心 S3。这就是我投票的原因。
    【解决方案2】:

    来自 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())
    

    【讨论】:

      【解决方案3】:

      如果有人像我一样发现了这一点: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() 中,因为它已在类似问题中提出),因为这将更改 ContentDisposition 标头使用相同存储的任何字段的后续文件上传。这可能不是您想要的。

      【讨论】:

      • 你应该是编码original_name的url,否则你会得到SignatureDoesNotMatch错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多