Wednesday, January 7, 2015

Using S3 to Serve and Store Your Django Project's Media Files

This blog post will show you how to set up your Django project to store, and serve, your media files from an S3 bucket. It assumes you already have an S3 bucket set up, and already know how to set up your Django project to serve static files from that bucket.

When I deployed my first Django project to Heroku, I found a lot of great resources and tutorials online for setting up an S3 bucket to serve my static files. But I couldn't find anything that touched on how to set up my project to store/serve media files from S3 as well. Luckily I came across a few helpful StackOverflow answers, but I've always wanted to write a blog post to explain the steps in 1 place. This is that post!

Step 1


If you're using S3 to serve static files, you might already have boto and storages installed. If not, do the following:
pip install django-storages
pip install boto
Then, add storages and boto to your INSTALLED_APPS in your settings file.

django-storages is a collection of custom storage backends for Django. You can read more about it here. The backend we'll be using requires the boto library. You can read more about boto here. This custom backend allows your static/media files to easily be sent to your S3 bucket.

Step 2


Add the following lines to your settings file:
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_STORAGE_BUCKET_NAME = 'aws_bucket_name'
AWS_ACCESS_KEY_ID = 'aws_access_key_id'
AWS_SECRET_ACCESS_KEY = 'aws_secret_access_key'
S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
MEDIA_URL = S3_URL
If you're already using S3 to serve static files, you might have the following lines as well:
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATIC_URL = S3_URL
The DEFAULT_FILE_STORAGE is where the magic happens. Updating this setting overwrites Django's default storage system, which implements file storage on the local filesystem.

You'll notice the STATIC_URL and MEDIA_URL are the same in this example. That's because S3 will store your static and media files in the same folder by default. If you want to store your files in different folders, like you would on your local machine, follow the next step.

Step 3


Create a s3utils.py file in your project configuration folder. Add the following lines to it:
from storages.backends.s3boto import S3BotoStorage

StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static')
MediaRootS3BotoStorage  = lambda: S3BotoStorage(location='media')
Then, update the DEFAULT_FILE_STORAGE and STATICFILES_STORAGE settings to the following:
DEFAULT_FILE_STORAGE = 'yourproject.s3utils.MediaRootS3BotoStorage'
STATICFILES_STORAGE = 'yourproject.s3utils.StaticRootS3BotoStorage'
Lastly, update your STATIC_URL and MEDIA_URL settings to reference the new folder. For example:
STATIC_URL = S3_URL + 'static/'
MEDIA_URL = S3_URL + 'media/'
It should be that easy. If you have any questions, or if you notice anything in this tutorial that needs to be updated, you can join the discussion on Wikivinci. Or, feel free to email me at dylanbfox[at]gmail.com.