# HG changeset patch -- Bitbucket.org # Project django-storages # URL http://bitbucket.org/david/django-storages/overview # User David Larlet # Date 1213286311 -7200 # Node ID 1cbeb2a32019b971ac86d5b9370d5316268d99dc Add existing S3Storage --- /dev/null +++ b/S3Storage.py @@ -0,0 +1,92 @@ +from mimetypes import guess_type +import os + +from django.core.exceptions import ImproperlyConfigured +from django.core.filestorage.base import Storage, RemoteFile +from django.core.filestorage.filesystem import FileSystemStorage +from django.utils.functional import curry +from django.conf import settings + +ACCESS_KEY_NAME = 'AWS_ACCESS_KEY_ID' +SECRET_KEY_NAME = 'AWS_SECRET_ACCESS_KEY' +AWS_HEADERS = 'AWS_HEADERS' + +try: + from S3 import AWSAuthConnection, QueryStringAuthGenerator +except ImportError: + raise ImproperlyConfigured, "Could not load amazon's S3 bindings.\ + \nSee http://developer.amazonwebservices.com/connect/entry.jspa?externalID=134" + +class S3Storage(Storage): + """Amazon Simple Storage Service""" + + def __init__(self, bucket=settings.AWS_STORAGE_BUCKET_NAME, + access_key=None, secret_key=None, acl='public-read', + calling_format=settings.AWS_CALLING_FORMAT): + self.bucket = bucket + self.acl = acl + + if not access_key and not secret_key: + access_key, secret_key = self._get_access_keys() + + self.connection = AWSAuthConnection(access_key, secret_key, + calling_format=calling_format) + self.generator = QueryStringAuthGenerator(access_key, secret_key, + calling_format=calling_format, is_secure=False) + + self.headers = getattr(settings, AWS_HEADERS, {}) + + def _get_access_keys(self): + access_key = getattr(settings, ACCESS_KEY_NAME, None) + secret_key = getattr(settings, SECRET_KEY_NAME, None) + if (access_key or secret_key) and (not access_key or not secret_key): + access_key = os.environ.get(ACCESS_KEY_NAME) + secret_key = os.environ.get(SECRET_KEY_NAME) + + if access_key and secret_key: + # Both were provided, so use them + return access_key, secret_key + + return None, None + + def _get_connection(self): + return AWSAuthConnection(*self._get_access_keys()) + + def _put_file(self, filename, raw_contents): + content_type = guess_type(filename)[0] or "application/x-octet-stream" + self.headers.update({'x-amz-acl': self.acl, 'Content-Type': content_type}) + response = self.connection.put(self.bucket, filename, raw_contents, self.headers) + + def url(self, filename): + return self.generator.make_bare_url(self.bucket, filename) + + path = url + + def filesize(self, filename): + response = self.connection.make_request('HEAD', self.bucket, filename) + return int(response.getheader('Content-Length')) + + def open(self, filename, mode='rb'): + response = self.connection.get(self.bucket, filename) + writer = curry(self._put_file, filename) + return RemoteFile(self, response.object.data, mode, writer) + + def exists(self, filename): + response = self.connection.make_request('HEAD', self.bucket, filename) + return response.status == 200 + + def save(self, filename, raw_contents): + filename = self.get_available_filename(filename) + self._put_file(filename, raw_contents) + return filename + + ## UNCOMMENT BELOW IF NECESSARY + + #def delete(self, filename): + # """ Do not delete default images. """ + # if not filename.endswith('default.jpg') and not filename.endswith('guest.jpg'): + # self.connection.delete(self.bucket, filename) + + #def get_available_filename(self, filename): + # """ Overwrite existing file with the same name. """ + # return filename --- /dev/null +++ b/FTPStorage.py @@ -0,0 +1,1 @@ +# Work in progress --- /dev/null +++ b/S3BotoStorage.py @@ -0,0 +1,1 @@ +# should not be too hard to adapt S3Storage