簡體   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