david / django-storages

Support for many storages (S3, MogileFS, etc) in Django.

Clone this repository (size: 160.0 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

Up to file-list S3Storage.py:

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