[英]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.