Storing images (or files) on S3 with Django
There comes a time when you need to upload stuff to your server via your Django app. You can upload it to the machine serving up your app (which isn’t a good idea in most cases) or upload it to a server/service which specializes in delivering you content. Enter S3.
Django and S3 to play nice is pretty straightforward. This tutorial/guide/journal assumes a few things.
- You already have a basic Django app of somes sorts and need to add image upload functionality
- You know how to configure your AWS S3 account and a bucket configured
- Since (in my case) this is specific to images I also have Pillow installed
The majority of this magic is provided via two libraries
Pip install these libraries…
pip install django-storages
pip install boto
Once you got this done, modify your settings.py
file.
INSTALLED_APPS = (
#...
'storages',
#...
)
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_S3_SECURE_URLS = False # HTTP vs HTTPS
AWS_QUERYSTRING_AUTH = False # Set this to False if you do not want the file being cached as a result of a unique query string being returned for your requests
AWS_S3_ACCESS_KEY_ID = os.getenv('AWS_S3_ACCESS_KEY_ID') # Your Amazon Web Services access key, as a string.
AWS_S3_SECRET_ACCESS_KEY = os.getenv('AWS_S3_SECRET_ACCESS_KEY') # Your Amazon Web Services secret access key, as a string.
AWS_STORAGE_BUCKET_NAME = 'yourbucketsname'
Next modify your models.py
file in the application you want to add this to
import os
from django.db import models
def upload_avatar_to(obj, filename):
filename_base, filename_ext = os.path.splitext(filename)
s3filename = "profiles/{}{}{}".format(obj.first_name.lower(), obj.last_name.lower(), filename_ext.lower())
return s3filename
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
image = models.ImageField(blank=True, upload_to=upload_avatar_to)
def __unicode__(self):
return '{} {}'.format(self.first_name, self.last_name)
class Meta:
unique_together = ('first_name', 'last_name')
ordering = ['last_name', 'first_name']
That is it… At this point your images will get punted to S3.