[英]collecstatic modified files using s3boto and django-storages
[英]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.metadata
和test.key.set_metadata
而不是In [9]
。 他们都没有这样做。
如何设置正确的 Content-Type?
如果您查看类S3BotoStorageFile
和函数write
的源代码,则标头仅从 2 个位置更新,
upload_headers.update(self._storage.headers)
其中self._storage.headers
取自AWS_HEADERS
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
= ContentType
, Content-Dispostion
= ContentDispostion
等等。希望这会Content-Dispostion
帮助!
我遇到了类似的问题 - 我想为使用django-storages
storages 上传到 S3 的所有文件设置 header ,而不依赖于根据文件名猜测 mime 类型的默认库方法。
请注意,您可以调整 header 的设置方式,而不必像我一样修复它(我的情况是特定的)。
这对我有用:
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
ManagedS3BotoS3Storage
:class SomeCoolModel(models.Model):
file = models.FileField(
storage=ManagedS3BotoS3Storage(bucket="my-awesome-S3-bucket"),
upload_to="my_great_path_to_file",
)
python manage.py makemigrations
。 就是这样,在这之后我上传的所有文件都使用Content-Type: "application/octet-stream
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.