繁体   English   中英

使用带有 S3boto 后端的 django-storages 保存到 S3 时如何设置“Content-Type”?

[英]How do you set "Content-Type" when saving to S3 using django-storages with S3boto backend?

我使用django-storages storages 和s3boto作为后端。

我有一个带有两个文件夹的存储桶 - 一个用于static ,一个用于media 我使用django-s3-folder-storage实现了这一点。

除了使用 model 保存到 S3 之外,我还想实现图像调整大小和缓存 function 以将文件保存到 S3。 为此,我直接与我的 S3 存储桶进行交互。 该代码有效,但未在 S3 上设置Content-Type

在 iPython 中:

In [2]: from s3_folder_storage.s3 import DefaultStorage

In [3]: s3media = DefaultStorage()

In [4]: s3media
Out[4]: <s3_folder_storage.s3.DefaultStorage at 0x4788780>

测试我们正在访问正确的存储桶 - storage_test是我之前创建的:

In [5]: s3media.exists('storage_test')
Out[5]: True

In [6]: s3media.open("test.txt", "w")
Out[6]: <S3BotoStorageFile: test.txt>

In [7]: test = s3media.open("test.txt", "w")

In [8]: test
Out[8]: <S3BotoStorageFile: test.txt>

In [9]: test.key.content_type = "text/plain"

In [10]: test.write("...")

In [11]: test.close()

In [12]: test = s3media.open("test.txt", "w")

In [13]: test.key.content_type
Out[13]: 'binary/octet-stream'

我也尝试过使用test.key.metadatatest.key.set_metadata而不是In [9] 他们都没有这样做。

如何设置正确的 Content-Type?

如果您查看类S3BotoStorageFile和函数write的源代码,则标头仅从 2 个位置更新,

  1. upload_headers.update(self._storage.headers)其中self._storage.headers取自AWS_HEADERS
  2. self._storage.default_acl

在函数_flush_write_buffer只考虑self._storage.headers 检查行headers = self._storage.headers.copy()

所以更新test.key.content_type将不起作用。

而不是In [9]:test.key.content_type = "text/plain" In [9]:尝试使用test._storage.headers['Content-Type'] = 'text/plain' ,它应该可以工作。

根据此答案, Content-Type 不是元数据,而是您在上传文件时设置的标头。

现在您可以使用django-storages >= 1.4并且它会自动猜测 mime 类型。

这仅适用于 Boto3,不适用于 Boto。 如果您想设置这些标头,则需要像这样访问对象,file_ 是指具有存储设置的 FileField 以使用来自 django-storages 的 Boto3:

file_.storage.object_parameters = { 'ContentType': 'text/plain' }

注意:它要求标题名称是驼峰式的,所以Content-Type = ContentTypeContent-Dispostion = ContentDispostion等等。希望这会Content-Dispostion帮助!

我遇到了类似的问题 - 我想为使用django-storages storages 上传到 S3 的所有文件设置 header ,而不依赖于根据文件名猜测 mime 类型的默认库方法。

请注意,您可以调整 header 的设置方式,而不必像我一样修复它(我的情况是特定的)。

这对我有用:

  1. 实现自定义文件管理器:
import os

from storages.backends.s3boto3 import S3Boto3Storage


class ManagedS3BotoS3Storage(S3Boto3Storage):
    def _save(self, name, content):
        cleaned_name = self._clean_name(name)
        name = self._normalize_name(cleaned_name)
        params = self._get_write_parameters(name, content)

        content_type = "application/octet-stream". # Content-Type that I wanted to have for each file
        params["ContentType"] = content_type

        encoded_name = self._encode_name(name)
        obj = self.bucket.Object(encoded_name)
        if self.preload_metadata:
            self._entries[encoded_name] = obj

        content.seek(0, os.SEEK_SET)
        obj.upload_fileobj(content, ExtraArgs=params)

        return cleaned_name

  1. 在 model 中使用ManagedS3BotoS3Storage
class SomeCoolModel(models.Model):
    file = models.FileField(
        storage=ManagedS3BotoS3Storage(bucket="my-awesome-S3-bucket"),
        upload_to="my_great_path_to_file",
    )
  1. 运行python manage.py makemigrations

就是这样,在这之后我上传的所有文件都使用Content-Type: "application/octet-stream

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM