Django

Code

Ticket #6390: S3_6390.20080225.py

File S3_6390.20080225.py, 3.2 kB (added by david, 6 months ago)

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

Line 
1 from mimetypes import guess_type
2 from StringIO import StringIO
3 import urlparse
4 import os
5
6 from django.core.exceptions import ImproperlyConfigured
7 from django.core.filestorage.base import Backend, RemoteFile
8 from django.core.filestorage.filesystem import FileSystemBackend
9 from django.utils.functional import curry
10
11 ACCESS_KEY_NAME = 'AWS_ACCESS_KEY_ID'
12 SECRET_KEY_NAME = 'AWS_SECRET_ACCESS_KEY'
13
14 try:
15     from _lib.amazon.S3 import AWSAuthConnection, QueryStringAuthGenerator, CallingFormat
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 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