david / django-storages
Support for many storages (S3, MogileFS, etc) in Django.
Clone this repository (size: 192.4 KB): HTTPS / SSH
$ hg clone http://code.welldev.org/django-storages
Changed (Δ3.5 KB):
raw changeset »
FTPStorage.py (1 lines added, 0 lines removed)
S3BotoStorage.py (1 lines added, 0 lines removed)
S3Storage.py (92 lines added, 0 lines removed)
Up to file-list FTPStorage.py:
1 |
# Work in progress |
Up to file-list S3BotoStorage.py:
1 |
# should not be too hard to adapt S3Storage |
1 |
from mimetypes import guess_type |
|
2 |
import os |
|
3 |
||
4 |
from django.core.exceptions import ImproperlyConfigured |
|
5 |
from django.core.filestorage.base import Storage, RemoteFile |
|
6 |
from django.core.filestorage.filesystem import FileSystemStorage |
|
7 |
from django.utils.functional import curry |
|
8 |
from django.conf import settings |
|
9 |
||
10 |
ACCESS_KEY_NAME = 'AWS_ACCESS_KEY_ID' |
|
11 |
SECRET_KEY_NAME = 'AWS_SECRET_ACCESS_KEY' |
|
12 |
AWS_HEADERS = 'AWS_HEADERS' |
|
13 |
||
14 |
try: |
|
15 |
from S3 import AWSAuthConnection, QueryStringAuthGenerator |
|
16 |
except ImportError: |
|
17 |
raise ImproperlyConfigured, "Could not load amazon's S3 bindings.\ |
|
18 |
\nSee http://developer.amazonwebservices.com/connect/entry.jspa?externalID=134" |
|
19 |
||
20 |
class S3Storage(Storage): |
|
21 |
"""Amazon Simple Storage Service""" |
|
22 |
||
23 |
def __init__(self, bucket=settings.AWS_STORAGE_BUCKET_NAME, |
|
24 |
access_key=None, secret_key=None, acl='public-read', |
|
25 |
calling_format=settings.AWS_CALLING_FORMAT): |
|
26 |
self.bucket = bucket |
|
27 |
self.acl = acl |
|
28 |
||
29 |
if not access_key and not secret_key: |
|
30 |
access_key, secret_key = self._get_access_keys() |
|
31 |
||
32 |
self.connection = AWSAuthConnection(access_key, secret_key, |
|
33 |
calling_format=calling_format) |
|
34 |
self.generator = QueryStringAuthGenerator(access_key, secret_key, |
|
35 |
calling_format=calling_format, is_secure=False) |
|
36 |
||
37 |
self.headers = getattr(settings, AWS_HEADERS, {}) |
|
38 |
||
39 |
def _get_access_keys(self): |
|
40 |
access_key = getattr(settings, ACCESS_KEY_NAME, None) |
|
41 |
secret_key = getattr(settings, SECRET_KEY_NAME, None) |
|
42 |
if (access_key or secret_key) and (not access_key or not secret_key): |
|
43 |
access_key = os.environ.get(ACCESS_KEY_NAME) |
|
44 |
secret_key = os.environ.get(SECRET_KEY_NAME) |
|
45 |
||
46 |
if access_key and secret_key: |
|
47 |
# Both were provided, so use them |
|
48 |
return access_key, secret_key |
|
49 |
||
50 |
return None, None |
|
51 |
||
52 |
def _get_connection(self): |
|
53 |
return AWSAuthConnection(*self._get_access_keys()) |
|
54 |
||
55 |
def _put_file(self, filename, raw_contents): |
|
56 |
content_type = guess_type(filename)[0] or "application/x-octet-stream" |
|
57 |
self.headers.update({'x-amz-acl': self.acl, 'Content-Type': content_type}) |
|
58 |
response = self.connection.put(self.bucket, filename, raw_contents, self.headers) |
|
59 |
||
60 |
def url(self, filename): |
|
61 |
return self.generator.make_bare_url(self.bucket, filename) |
|
62 |
||
63 |
path = url |
|
64 |
||
65 |
def filesize(self, filename): |
|
66 |
response = self.connection.make_request('HEAD', self.bucket, filename) |
|
67 |
return int(response.getheader('Content-Length')) |
|
68 |
||
69 |
def open(self, filename, mode='rb'): |
|
70 |
response = self.connection.get(self.bucket, filename) |
|
71 |
writer = curry(self._put_file, filename) |
|
72 |
return RemoteFile(self, response.object.data, mode, writer) |
|
73 |
||
74 |
def exists(self, filename): |
|
75 |
response = self.connection.make_request('HEAD', self.bucket, filename) |
|
76 |
return response.status == 200 |
|
77 |
||
78 |
def save(self, filename, raw_contents): |
|
79 |
filename = self.get_available_filename(filename) |
|
80 |
self._put_file(filename, raw_contents) |
|
81 |
return filename |
|
82 |
||
83 |
## UNCOMMENT BELOW IF NECESSARY |
|
84 |
||
85 |
#def delete(self, filename): |
|
86 |
# """ Do not delete default images. """ |
|
87 |
# if not filename.endswith('default.jpg') and not filename.endswith('guest.jpg'): |
|
88 |
# self.connection.delete(self.bucket, filename) |
|
89 |
||
90 |
#def get_available_filename(self, filename): |
|
91 |
# """ Overwrite existing file with the same name. """ |
|
92 |
# return filename |
