Changes between Initial Version and Version 1 of AmazonSimpleStorageService


Ignore:
Timestamp:
Jun 7, 2007, 7:38:08 PM (17 years ago)
Author:
dobesv@…
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AmazonSimpleStorageService

    v1 v1  
     1
     2Here's a class I created to integrate my site with amazon's storage service.
     3
     4I like this because in the admin interface it looks pretty much like a file field and you can just click to upload.  In theory you could integrate it into any oldforms system.  Note that you have to set the amazon key, bucket, etc. manually, and that you have to put your amazon access keys into your site's settings module.
     5
     6This hasn't been tested extensively, so I invite you to contribute any fixes right here on the page.  Maybe the django gods will see fit to include this right into django.
     7
     8{{{
     9from amazon import S3
     10from django.conf import settings
     11from django.db import models
     12from mimetypes import guess_type
     13from mx.DateTime import now
     14from django.core import validators
     15from django import oldforms
     16from django.dispatch import dispatcher
     17from django.utils.functional import curry
     18from django.utils.translation import gettext_lazy
     19from django.db.models import signals
     20import os
     21
     22conn = S3.AWSAuthConnection(settings.AWS_ACCESS_KEY_ID,
     23                            settings.AWS_SECRET_ACCESS_KEY)
     24generator = S3.QueryStringAuthGenerator(settings.AWS_ACCESS_KEY_ID,
     25                                        settings.AWS_SECRET_ACCESS_KEY)
     26
     27class S3FileField(models.FileField):
     28    def __init__(self, verbose_name=None, name=None, bucket='', is_image=False, **kwargs):
     29        models.FileField.__init__(self, verbose_name, name, upload_to="s3", **kwargs)
     30        self.bucket = bucket
     31        self.is_image = is_image
     32
     33    def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
     34        field_list = models.Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)
     35        if not self.blank:
     36            if rel:
     37                # This validator makes sure FileFields work in a related context.
     38                class RequiredFileField(object):
     39                    def __init__(self, other_field_names, other_file_field_name):
     40                        self.other_field_names = other_field_names
     41                        self.other_file_field_name = other_file_field_name
     42                        self.always_test = True
     43                    def __call__(self, field_data, all_data):
     44                        if not all_data.get(self.other_file_field_name, False):
     45                            c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, gettext_lazy("This field is required."))
     46                            c(field_data, all_data)
     47                # First, get the core fields, if any.
     48                core_field_names = []
     49                for f in opts.fields:
     50                    if f.core and f != self:
     51                        core_field_names.extend(f.get_manipulator_field_names(name_prefix))
     52                # Now, if there are any, add the validator to this FormField.
     53                if core_field_names:
     54                    field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))
     55            else:
     56                v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, gettext_lazy("This field is required."))
     57                v.always_test = True
     58                field_list[0].validator_list.append(v)
     59                field_list[0].is_required = field_list[1].is_required = False
     60
     61        return field_list
     62   
     63    def get_internal_type(self):
     64        return "FileField"
     65   
     66    def contribute_to_class(self, cls, name):
     67        super(S3FileField, self).contribute_to_class(cls, name)
     68        #models.CharField(maxlength=200, blank=self.blank, null=self.null).contribute_to_class(cls, "%s_filename"%(self.name))
     69        models.CharField(maxlength=200, blank=self.blank, null=self.null).contribute_to_class(cls, "%s_key"%(self.name))
     70        models.CharField(maxlength=200, blank=self.blank, null=self.null, default=settings.DEFAULT_BUCKET).contribute_to_class(cls, "%s_bucket"%(self.name))
     71        models.CharField(maxlength=200, blank=True, null=True, default="").contribute_to_class(cls, "%s_content_type"%(self.name))
     72        models.IntegerField(blank=True, null=True).contribute_to_class(cls, "%s_size"%(self.name))
     73        if self.is_image:
     74            models.IntegerField(blank=True, null=True).contribute_to_class(cls, "%s_width"%(self.name))
     75            models.IntegerField(blank=True, null=True).contribute_to_class(cls, "%s_height"%(self.name))
     76       
     77        # Getter for the file url
     78        def get_url(instance, field):
     79            return field.get_url(instance)
     80        setattr(cls, 'get_%s_url' % self.name, curry(get_url, field=self))
     81       
     82        dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)
     83
     84    def delete_file(self, instance):
     85        if getattr(instance, self.attname):
     86            bucket = self.get_bucket(instance)
     87            key = self.get_key(instance)
     88            conn.delete(bucket, key)
     89   
     90    def get_url(self, instance):
     91        print 'get_url called with instance %s'%instance
     92        bucket = self.get_bucket(instance)
     93        key = self.get_key(instance)
     94        print 'key %s bucket %s'%(key, bucket)
     95        import sys
     96        sys.stdout.flush()
     97        if bucket and key:
     98            url = generator.make_bare_url(bucket, key)
     99            print 'url', url
     100            sys.stdout.flush()
     101            return url
     102        return None
     103               
     104    def get_bucket(self, instance):
     105        return getattr(instance, "%s_bucket"%self.name)
     106   
     107    def set_bucket(self, instance, bucket):   
     108        setattr(instance, "%s_bucket"%self.name, bucket)
     109       
     110    def get_key(self, instance):
     111        return getattr(instance, "%s_key"%self.name)
     112   
     113    def set_key(self, instance, key):   
     114        setattr(instance, "%s_key"%self.name, key)
     115       
     116    def get_content_type(self, instance):
     117        return getattr(instance, "%s_content_type"%self.name)
     118       
     119    def set_content_type(self, instance, content_type):   
     120        setattr(instance, "%s_content_type"%self.name, content_type)
     121       
     122    def get_size(self, instance):
     123        return getattr(instance, "%s_size"%self.name)
     124       
     125    def set_size(self, instance, size):   
     126        setattr(instance, "%s_size"%self.name, size)
     127       
     128    def get_filename(self, instance):
     129        return getattr(instance, self.name)
     130       
     131    def set_filename(self, instance, filename):   
     132        setattr(instance, self.name, filename)
     133       
     134    def get_width(self, instance):
     135        return getattr(instance, "%s_width"%self.name)
     136   
     137    def set_width(self, instance, width):   
     138        setattr(instance, "%s_width"%self.name, width)
     139       
     140    def get_height(self, instance):
     141        return getattr(instance, "%s_height"%self.name)
     142       
     143    def set_height(self, instance, height):   
     144        setattr(instance, "%s_height"%self.name, height)
     145               
     146    def get_manipulator_field_objs(self):
     147        if self.is_image: uploadType = oldforms.ImageUploadField
     148        else: uploadType = oldforms.FileUploadField
     149        return [uploadType, oldforms.HiddenField]
     150
     151    def get_manipulator_field_names(self, name_prefix):
     152        return [name_prefix + self.name + '_file', name_prefix + self.name]
     153
     154    def save_file(self, new_data, new_object, original_object, change, rel, save=True):
     155        upload_field_name = self.get_manipulator_field_names('')[0]
     156        if new_data.get(upload_field_name, False):
     157            if rel:
     158                new_content = new_data[upload_field_name][0]["content"]
     159                new_filename = new_data[upload_field_name][0]["filename"]
     160            else:
     161                new_content = new_data[upload_field_name]["content"]
     162                new_filename = new_data[upload_field_name]["filename"]
     163           
     164            self.set_filename(new_object, new_filename)
     165            key = new_data["%s_key"%self.name]
     166            bucket = new_data["%s_bucket"%self.name]
     167            if not bucket:
     168                bucket = self.bucket
     169            content_type = new_data["%s_content_type"%self.name]
     170            if new_filename and not content_type:
     171                content_type = guess_type(new_filename)[0]
     172                if not content_type:
     173                    content_type = "application/x-octet-stream"
     174            print 'Uploading %d bytes of data to bucket %s key %s filename %s'%(len(new_content), bucket, key, new_filename)
     175            conn.put(bucket, key, S3.S3Object(new_content),
     176                     { 'x-amz-acl': 'public-read' , 'Content-Type': content_type})
     177            # TODO Calculate image width/height
     178           
     179
     180}}}
Back to Top