I am using django-storages
with s3boto
as a backend.
I have one bucket with two folders - one for static
and one for media
. I achieve this using django-s3-folder-storage
.
As well as saving to S3 using a model, I also want to implement an image-resize-and-cache function to save the files to S3. To do this I interact directly with my S3 bucket. The code works, but the Content-Type
isn't set on S3.
in 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>
Test we're accessing the right bucket - storage_test
is one I created earlier:
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'
I've also tried instead of In [9]
using test.key.metadata
and test.key.set_metadata
. None of them do it.
How do I set the correct Content-Type?
According to this answer, the Content-Type isn't metadata but rather headers that you set up when you upload the file.
Now you can use
django-storages >= 1.4
and it automatically guesses the mime types.If you go through the source code in class
S3BotoStorageFile
and functionwrite
, the header is updated from only 2 places,upload_headers.update(self._storage.headers)
whereself._storage.headers
is taken fromAWS_HEADERS
self._storage.default_acl
And in function
_flush_write_buffer
onlyself._storage.headers
is considered. Check for the lineheaders = self._storage.headers.copy()
So updating
test.key.content_type
will not work.Instead of
test.key.content_type = "text/plain"
atIn [9]:
try usingtest._storage.headers['Content-Type'] = 'text/plain'
, it should work.This is for Boto3 ONLY, not Boto. If you would like to set those headers, you will need to access the object like so, file_ is refereing to a FileField with storage setup to be using Boto3 from django-storages:
NOTE: it requires header names to be camelcase, so
Content-Type
=ContentType
,Content-Dispostion
=ContentDispostion
etc. Hope this helps!