## On your app.forms.py from member.models import UserProfile from django import forms import datetime import base64 import hmac, sha, simplejson class S3UploadForm(forms.Form): """ http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434 """ key = forms.CharField(widget = forms.HiddenInput) AWSAccessKeyId = forms.CharField(widget = forms.HiddenInput) acl = forms.CharField(widget = forms.HiddenInput) success_action_redirect = forms.CharField(widget = forms.HiddenInput) policy = forms.CharField(widget = forms.HiddenInput) signature = forms.CharField(widget = forms.HiddenInput) content_type = forms.CharField(widget = forms.HiddenInput) file = forms.FileField() def __init__(self, aws_access_key, aws_secret_key, bucket, key, expires_after = datetime.timedelta(days = 30), acl = 'public-read', success_action_redirect = None, content_type = '', min_size = 0, max_size = None, ): self.aws_access_key = aws_access_key self.aws_secret_key = aws_secret_key self.bucket = bucket self.key = key self.expires_after = expires_after self.acl = acl self.success_action_redirect = success_action_redirect self.content_type = content_type self.min_size = min_size self.max_size = max_size policy = base64.b64encode(self.calculate_policy()) signature = self.sign_policy(policy) initial = { 'key': self.key, 'AWSAccessKeyId': self.aws_access_key, 'acl': self.acl, 'policy': policy, 'signature': signature, 'content_type': self.content_type, } if self.success_action_redirect: initial['success_action_redirect'] = self.success_action_redirect super(S3UploadForm, self).__init__(initial = initial) if self.content_type: # we change the name of the field to the S3 required self.fields['content_type'].widget.attrs.update({'name':'Content-Type'}) # We need to manually rename the content_type field to content_type if self.max_size: self.fields['MAX_SIZE'] = forms.CharField(widget=forms.HiddenInput) self.initial['MAX_SIZE'] = self.max_size # Don't show success_action_redirect if it's not being used if not self.success_action_redirect: del self.fields['success_action_redirect'] def add_prefix(self, field_name): # Hack to use the S3 required field name if field_name == 'content_type' and self.content_type: field_name = 'Content-Type' return super(S3UploadForm, self).add_prefix(field_name) def as_html(self): """ Use this instead of as_table etc, because S3 requires the file field come AFTER the hidden fields, but Django's normal form display methods position the visible fields BEFORE the hidden fields. """ html = ''.join(map(unicode, self.hidden_fields())) html += unicode(self['file']) return html def as_form_html(self, prefix='', suffix=''): html = """

%s

""".strip() % (self.action(), self.as_html()) return html def is_multipart(self): return True def action(self): return 'https://%s.s3.amazonaws.com/' % self.bucket def calculate_policy(self): conditions = [ {'bucket': self.bucket}, {'acl': self.acl}, ['starts-with', '$key', self.key.replace('${filename}', '')], ["starts-with", "$Content-Type", self.content_type], ] if self.content_type: conditions.append( ['starts-with','$Content-Type',self.content_type] ) if self.max_size: conditions.append( ['content-length-range',self.min_size,self.max_size] ) if self.success_action_redirect: conditions.append( {'success_action_redirect': self.success_action_redirect}, ) policy_document = { "expiration": ( datetime.datetime.now() + self.expires_after ).isoformat().split('.')[0] + 'Z', "conditions": conditions, } return simplejson.dumps(policy_document, indent=2) def sign_policy(self, policy): return base64.b64encode( hmac.new(self.aws_secret_key, policy, sha).digest() ) ## On a app.view.py def profile_image(request,template_name=None,user=None): s3uploadform = S3UploadForm( settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY, settings.AWS_STORAGE_BUCKET_NAME, 'uploads/'+user+'_photo.jpg', content_type='image/', success_action_redirect = 'http://domain/johnTheUser/upload_success', max_size=734003, # 700 kbs expires_after = datetime.timedelta(days=99999) #forever! ) context = {'form':s3uploadform} return render_to_response(template_name,context, context_instance=RequestContext(request)) ## On a template.html
{{form.key}} {{form.AWSAccessKeyId}} {{form.acl}} {{form.success_action_redirect}} {{form.policy}} {{form.signature}} {{form.content_type}} {{form.file}}