Using ManifestStaticFilesStorage with Django Storages and Amazon S3

Many of the Django websites I’ve been working on lately are being deployed to Amazon Elastic Compute Cloud (EC2) servers and utilize Amazon Simple Storage Service (S3) for hosting static files.

The simplest method I’ve found for integrating Amazon S3 for hosting static media inside a Django project is to use the django-storages project to handle creating the necessary storage backend. I setup the static file storage backend to use the S3Botostorage backend via settings:

And the next time I run Collectstatic all of my static assets are pushed to the configured S3 account and static files served from there when I use the static templatetag.

For the most part this system runs smoothly but I have run into a couple of common issues with each project:

Static files are loaded into the root of the S3 Bucket.

Most of my clients will use the same bucket for static assets as well as user uploads. So, how do we get the static files into a key prefix (the S3 version of a directory) on Amazon S3? For that I make use of the AWS LOCATION  settings tag made available by django-storages S3 backend.

With that settings variable in place set all of my static files will go into the key prefix I indicated when I run Collectstatic. So, for example, if I set AWS_LOCATION = 'static'  in my Django settings then all of my static files will now be available in https://mybucket.s3.amazonaws.com/static/

Using Django’s ManifestStaticFilesStorage along with storages.backends.s3boto.S3BotoStorage.

I always configure storages with ‘Expires’ and ‘Cache-Control’ headers set well into the future so that browsers know to cache the media which brings improved performance to the site as static files don’t have to be fetched on every page load.

However, I do want to be able to take advantage of Django’s ManifestStaticFilesStorage backend so that I can have Collectstatic “bust the cache” for my static files by renaming them when uploading new or updated files to S3. The problem I first ran into was that I’m already calling the S3BotoStorage backend with django-storages. I can’t define two separate storage backends!

Thankfully, the community of developers working on Django were wise enough to create a ManifestFilesMixin that we can utilize with S3BotoStorage and accomplish what we need. To get this working we’ll need to create a custom storage backend that brings these two classes together.

I create file named CustomS3BotoStorage.py (you can call it whatever you’d like). Inside that file I create a simple class that combines the ManifestFilesMixin and the S3BotoStorage class:

Then, I set the STATICFILES_STORAGE setting to point to my custom storage class:

With this custom class I can now have the benefits of django-storages with the cache busting of ManifestStaticFilesStorage.