A Django Form for creating a browser-based upload form that pushes files to Amazon S3. See http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1434
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | from django import forms
import datetime
import base64
import hmac, sha, simplejson
"""
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">
"""
class S3UploadForm(forms.Form):
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)
# We need to manually rename the Content_Type field to Content-Type
self.fields['Content-Type'] = self.fields['Content_Type']
del self.fields['Content_Type']
# 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 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.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()
)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 4 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.