deploying a django app to heroku with easy static files on s3
15 Oct 2011
django and s3
This project doesn't necessarily require heroku, but I've been interested in the service as an easy way to deploy apps. I really like the idea of not having to set up a server with nginx, postgres, gunicorn, etc. The convenience of deploying just by pushing from git is awesome.
You can clone my sample project from github
git clone firstname.lastname@example.org:eknuth/django-heroku-s3-bootstrap-demo.git
Django on Heroku
Heroku used to be limited to ruby apps, but it has recently become much more flexible with the addition of the cedar stack. Now it supports python 2.7 and uses pip to install modules from a standard requirements.txt file. They have also started offering a free 5mb postgresql db to go along with their current freemium offering, which is fantastic. That doesn't sound like a lot of space, but you'd be surprised how much information you can cram into 5 mb.
You can follow the django instructions from heroku here:
If you are using macosx, or virtualenv uses python 2.6 by default, I would suggest specifying 2.7 when you create the environment. Heroku is using 2.7 and will complain about pip installing importlib which was not included by default in python 2.6.
virtualenv --no-site-packages . -p /usr/local/bin/python2.7
Open the site on heroku using the "heroku open" command and verify that you get the django welcome screen. You should have no urls configured.
Admin and Static Files
You should now have a working empty project. Let's turn on the django admin app and fire up the development server.
As a side note, this config will import settings from settings_local.py, if it exists and overwrite the ones in settings.py. This local settings file is not committed to the repo and won't get deployed to heroku.
Follow the instructions to install the django admin app
and then run manage.py syncdb and then runserver. If everything went ok, you should be able to log in to your admin console.
Now, commit and push your app to heroku. Run the manage.py commands on heroku and magically your admin console is live on the web.
Twitter Bootstrap and view
Now, lets getting started with a template and a home view. We can use the totally awesome twitter bootstrap project
Create a templates folder in your project root. Clone the project from github and copy hero.html from the examples directory into your new templates directory.
Now let's create a view and wire up that template to a url. Now is the time to add on a django project that will make things easier for us. I really love the render_to decorator from django-annoying
. Run "pip install django-annoying", and it will be ready to go. Don't forget to save your updated requirements with a "pip freeze >requirements.txt".
Add the template dir and a little snippet of python to use relative paths. This will make life easier in the future.
In the urls.py file, uncomment the following home view: url(r'^$', 'om.views.home', name='home'), And create a views.py file to grab the template and render it.
Now when you open the app on your development server, you get an actual "hello world" page. Unfortunately we are missing the css file, so it is unstyled. In your root project, create a static folder and inside that create another folder named css. Copy bootstrap.css into static/css.
To reference this css file, edit hero.html and change the line with bootstrap.css to this:
<link href="css/bootstrap.css" rel="stylesheet">
In order to make the STATIC_URL template tag work, we need to update STATICFILES_DIRS in settings.py to:
STATICFILES_DIRS = ( os.path.join(SITE_ROOT, 'static'),)
We also need add some template context processors with this:
TEMPLATE_CONTEXT_PROCESSORS = (
When we open the page served from our development server, we are good to go. The page is styled and looks awesome.
Static Files on Heroku
Amazon provides an excellent service for doing just that. Amazon's web services and the simple storage system are cheap and easy to use. There is also an excellent module for using s3 with django's static files app and the collectstatic management command with s3 as a backend. django-storages
makes it incredibly simple to use s3 for our static files.
django-storages and boto
First we want to install the module with "pip install django-storages" and add 'storages' to your INSTALLED_APPS tuple and set your storage type with:
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
We will also need to install boto, the python module for dealing with s3. Use "pip install boto" for that.
Log in to the amazon web services management console and create a new bucket. Add the name of the bucket and your access keys to settings.py like this:
AWS_ACCESS_KEY_ID = 'ACCESS KEY'
AWS_SECRET_ACCESS_KEY = 'SECRET'
AWS_STORAGE_BUCKET_NAME = 'django-blog
set up the s3 bucket
Look at the bucket properties and grab the url for the bucket. Update your STATIC_URL setting to point to the bucket. In this case it will look like this:
STATIC_URL = 'https://s3.amazonaws.com/django-blog/'
Now run manage.py collectstatic and you will see all the files being copied to your bucket. Freeze your requirements file and commit your repo. Now when you push to heroku, you should see your website with the bootstrap.css file pulled from s3.