Ticket #6390: S3_6390.20080225.py

File S3_6390.20080225.py, 3.2 KB (added by David Larlet, 16 years ago)

Functional S3 backend, use only Amazon's S3 lib (warning it overwrites filename)

Line 
1from mimetypes import guess_type
2from StringIO import StringIO
3import urlparse
4import os
5
6from django.core.exceptions import ImproperlyConfigured
7from django.core.filestorage.base import Backend, RemoteFile
8from django.core.filestorage.filesystem import FileSystemBackend
9from django.utils.functional import curry
10
11ACCESS_KEY_NAME = 'AWS_ACCESS_KEY_ID'
12SECRET_KEY_NAME = 'AWS_SECRET_ACCESS_KEY'
13
14try:
15 from _lib.amazon.S3 import AWSAuthConnection, QueryStringAuthGenerator, CallingFormat
16except ImportError:
17 raise ImproperlyConfigured, "Could not load Amazon's S3 bindings.\
18 \nSee http://developer.amazonwebservices.com/connect/entry.jspa?externalID=134"
19
20class S3Backend(Backend):
21 """Amazon Simple Storage Service"""
22
23 def __init__(self, bucket, access_key=None, secret_key=None,
24 acl='public-read', calling_format=CallingFormat.REGULAR):
25 self.bucket = bucket
26 self.acl = acl
27
28 if not access_key and not secret_key:
29 access_key, secret_key = self._get_access_keys()
30
31 self.connection = AWSAuthConnection(access_key, secret_key,
32 calling_format=calling_format)
33 self.generator = QueryStringAuthGenerator(access_key, secret_key,
34 calling_format=calling_format, is_secure=False)
35
36 def _get_access_keys(self):
37 access_key = getattr(settings, ACCESS_KEY_NAME, None)
38 secret_key = getattr(settings, SECRET_KEY_NAME, None)
39 if (access_key or secret_key) and (not access_key or not secret_key):
40 access_key = os.environ.get(ACCESS_KEY_NAME)
41 secret_key = os.environ.get(SECRET_KEY_NAME)
42
43 if access_key and secret_key:
44 # Both were provided, so use them
45 return access_key, secret_key
46
47 return None, None
48
49 def _get_connection(self):
50 return AWSAuthConnection(*self._get_access_keys())
51
52 def _put_file(self, filename, raw_contents):
53 content_type = guess_type(filename)[0] or "application/x-octet-stream"
54 headers = {'x-amz-acl': self.acl, 'Content-Type': content_type}
55 response = self.connection.put(self.bucket, filename, raw_contents, headers)
56
57 def get_absolute_url(self, filename):
58 return self.generator.make_bare_url(self.bucket, filename)
59
60 def get_filesize(self, filename):
61 response = self.connection.make_request('HEAD', self.bucket, filename)
62 return int(response.getheader('Content-Length'))
63
64 def open_file(self, filename, mode='rb'):
65 response = self.connection.get(self.bucket, filename)
66 writer = curry(self._put_file, filename)
67 return RemoteFile(self, response.object.data, mode, writer)
68
69 def file_exists(self, filename):
70 response = self.connection.make_request('HEAD', self.bucket, filename)
71 return response.status == 200
72
73 def save_file(self, filename, raw_contents):
74 filename = self.get_available_filename(filename)
75 self._put_file(filename, raw_contents)
76 return filename
77
78 def delete_file(self, filename):
79 self.connection.delete(self.bucket, filename)
80
81 def get_available_filename(self, filename):
82 """ Overwrite existing file with the same name. """
83 return filename
Back to Top