/
django_s3_upload.py
141 lines (114 loc) · 3.19 KB
/
django_s3_upload.py
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2014 dhilipsiva <dhilipsiva@gmail.com>
#
# Distributed under terms of the MIT license.
"""
I do media file upload to S3 very often in various projects.
So I thought I ll have a script always ready.
"""
"""
File: `myapp/settings.py`
Settings to be expected in `settings.py` file
"""
AWS_SECRET_KEY = 'secret_key'
AWS_ACCESS_KEY = 'access_key'
AWS_BUCKET = 'bucket'
AWS_BASE_URL = 'https://*.cloudfront.net'
AWS_EXPIRY_TIME = 60 * 30 # Half an hour
AWS_FORCE_HTTP = True
"""
`UPLOAD_TO_S3` flag to tell if the files are needed to be uploaded to S3.
During development, set this to `False`. And set to `True` in production.
"""
UPLOAD_TO_S3 = False
MEDIA_URL = ""
"""
A Wrapper around boto to upload to s3
File: `s3_uploader.py`
"""
import os
from boto.s3.connection import S3Connection
from boto.s3.key import Key
from django.conf import settings
if settings.UPLOAD_TO_S3:
conn = S3Connection(settings.AWS_ACCESS_KEY, settings.AWS_SECRET_KEY)
bucket = conn.get_bucket(settings.AWS_BUCKET)
def key_for_file(file):
"""
`key_for_file` generates an s3 key for the given file.
"""
return '/files/' + file._file.path.split('media/')[1]
def upload(file):
"""
This guy uploads the file from the given directory
"""
k = Key(bucket)
k.key = key_for_file(file)
k.set_contents_from_filename(file._file.path)
def temp_url(file):
"""
Function to generate a temproary AWS URL for fiven file object
"""
k = Key(bucket)
k.key = key_for_file(file)
return k.generate_url(
expires_in=settings.AWS_EXPIRY_TIME,
force_http=settings.AWS_FORCE_HTTP)
def process_file(file):
"""
Upload the file to s3
"""
if not settings.UPLOAD_TO_S3:
return file
try:
if not file.uploaded:
upload(file)
os.remove(file._file.path)
file.uploaded = True
file.save()
except Exception:
print "unable to upload file to s3"
finally:
return file
"""
File: myapp/models.py
File Model configuration
"""
from django.db import models
AWS_PREFIX = AWS_BASE_URL + MEDIA_URL
class MyFileModel(models.Model):
"""
This is the django model that you have file associated with.
Here I am assuming that `_file` is your FileField
"""
"""
Add a `uploaded` BooleanField to mark files if they
are uploaded to S3 or not
"""
uploaded = models.BooleanField(default=False)
@property
def get_url(self):
if self.uploaded:
"""
If the file is uploaded, return the temproary URL.
"""
return temp_url(self)
"""
Else the file URL or anything that is equivalent
"""
return self._file.url
"""
Management command to process existing files.
File: `myapp/managment/commands/upload_files.py`
Command: `python manage.py upload_files`
"""
from django.core.management.base import BaseCommand
files = MyFileModel.objects.filter(uploaded=False)
class Command(BaseCommand):
help = 'Re-process all the files from s3'
def handle(self, *args, **options):
for file in files:
file = process_file(file)