## 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 <input type="hidden" name="key" value="uploads/${filename}"> <input type="hidden" name="AWSAccessKeyId" value="YOUR_AWS_ACCESS_KEY"> <input type="hidden" name="acl" value="private"> <input type="hidden" name="success_action_redirect" value="http://localhost/"> <input type="hidden" name="policy" value="YOUR_POLICY_DOCUMENT_BASE64_ENCODED"> <input type="hidden" name="signature" value="YOUR_CALCULATED_SIGNATURE"> <input type="hidden" name="content_type" value="image/jpeg"> """ 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 = """ <form action="%s" method="post" enctype="multipart/form-data"> <p>%s <input type="submit" value="Upload"></p> </form> """.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 <html> <head> <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script> $(function(){ var max_size = {{form.max_size}}; var allowed_file_extensions = ['png','jpg']; var $upload_form = $('#image_upload_form'); $('#id_file').change(function(){ if($(this).val()){ file_name = $(this).val(); file_extension = file_name.substring(file_name.length - 3,file_name.length) if($.inArray(file_extension,allowed_file_extensions) < 0){ alert('Wrong file type'); return false; } if($(this)[0].files[0].size > max_size){ alert('The file is too big.') return false; } $upload_form.submit(); } else{ return false; } }) }) </script> </head> <form id='upload_form' action="https://{{BUCKET_NAME}}.amazonaws.com/" method="post" enctype="multipart/form-data"> {{form.key}} {{form.AWSAccessKeyId}} {{form.acl}} {{form.success_action_redirect}} {{form.policy}} {{form.signature}} {{form.content_type}} {{form.file}} <input type="submit" value="Save" /> </form> </html>