簡體   English   中英

"在 python 中為文件名(amazon S3)添加動態內容處置"

[英]Add Dynamic Content Disposition for file names(amazon S3) in python

我有一個將文件名保存為“uuid4().pdf”的 Django 模型。 其中 uuid4 為每個創建的實例生成一個隨機 uuid。 此文件名也存儲在同名的 amazon s3 服務器上。

我正在嘗試為我上傳到亞馬遜 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(),

 }

沒有運氣!

你們中的任何人都知道實現這一點。

來自 django-storages 的 S3Boto3Storage 的當前版本支持AWS_S3_OBJECT_PARAMETERS全局設置變量,它也允許修改ContentDisposition 但問題是,它按原樣應用於上傳到 s3 的所有對象,而且影響所有使用存儲的模型,這可能不是預期的結果。

以下黑客對我有用。

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

我猜您正在使用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()

如果有人發現這一點,就像我一樣:SO 上提到的所有解決方案都不適用於 Django 3.0。

S3Boto3Storage 的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標頭,用於后續使用相同字段的任何字段的文件上傳貯存。 這不是您可能想要的。

一種方法是將ResponseContentDisposition<\/code>參數提供給S3Boto3Storage.url()<\/code>方法。 在這種情況下,您不必創建自定義存儲。

示例模型:

class MyModel(models.Model):
    file = models.FileField(upload_to=generate_upload_path)
    original_filename = models.CharField(max_length=255)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM