How to migrate your existing Django project to Heroku


Wed 18 May 2016


Recently I had some fun with Heroku, the well known PaaS provider. I had a small personal Django project I use for invoicing that I ran locally with ./manage.py runserver when needed. That was a perfect candidate for the Heroku free plan because I need to access the app only occasionally.

In this tutorial I assume you have a basic knowledge of what Heroku is, and that you already know how to create and deploy a Python project on Heroku. In case you miss some basic information you can refer to the good Getting started tutorial on Heroku with Python.

How to structure your Django project for Heroku

Here I focus on my use case, which was to migrate an existing Django project on Heroku platform. My existing Django project was structured in accordance to the best practices I read in the wonderful Two Scoops of Django book, so my project structure was similar to this:

django/
├── project
│   ├── __init__.py
│   ├── settings
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── local.py
│   │   └── production.py
│   ├── urls.py
│   ├── wsgi.py
├── app
│   ├── __init__.py
│   ├── admin.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   ├── views.py
└── manage.py
requirements
├── base.txt
├── local.txt
└── production.txt

See how I have different settings for each deploy environment: one for local development, one for production. All common settings go in base.py.

See also how I have a different requirements file for each environment, for example I have django-debug-toolbar in local.txt, while I have psycopg2 in production.txt. All common requirements are in base.txt.

For Heroku I created a file heroku.txt under requirements/ directory with the following content:

-r base.txt

dj-database-url==0.3.0
psycopg2==2.6.1
whitenoise==2.0.2
django-storages==1.4.1
boto==2.38.0

How to configure your Django project for Heroku

On Heroku I will use Postgres as database backend (which is free , and dj-database-url to configure the database parameters using an environment variable, which is already set by Heroku.

I’ll also use whitenoise to handle static files directly from django and django-storages to handle media files on Amazon S3.

The first thing you have to do to tell Heroku you are deploying a python project is to put a requirements.txt file in the root of your git project. You can create a file with this content to include the requirements specific to Heroku:

-r requirements/heroku.txt

Then you have to do some modification to your settings, for deploy on Heroku platform:

# Parse database configuration from $DATABASE_URL
import dj_database_url
from os import environ

from .base import *

ALLOWED_HOSTS = ['yourappname.herokuapp.com']

DATABASES = {
 'default': dj_database_url.config()
}

WSGI_APPLICATION = 'yourproject.wsgi_heroku.application'
STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage'
STATIC_ROOT = root('static_root')

INSTALLED_APPS += ('storages',)
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
AWS_ACCESS_KEY_ID = environ['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = environ['AWS_SECRET_ACCESS_KEY']
AWS_STORAGE_BUCKET_NAME = 'yourbucketname'

Then you have to edit your wsgi.py file to make use of whitenoise for static files, the file whould look something like this. Save it in a different wsgi_heroku.py file:

import os
from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "yourproject.settings.heroku")

application = get_wsgi_application()
application = DjangoWhiteNoise(application)

Create an Heroku application for your Django project

Now you can create you Heroku application:

heroku create --region eu yourappname

In the root directory of your project you should have a Procfile, used by Heroku to know how to launch the web worker, in our case the Procfile should contain just one line like the following:

web: gunicorn --pythonpath django yourproject.wsgi_heroku --log-file -

Now push the code on Heroku:

git push heroku master

Then you can create the database schema with the usual migrate command, run on the Heroku instance:

heroku run python django/manage.py migrate

Migrating data

If you have some data to migrate you can use a couple of command from core Django

./manage.py dumpdata yourapp > yourapp/fixtures/app_data.json

Then you can import the data on Heroku instance:

heroku run python django/manage.py loaddata app_data

Media files on AWS S3

If your application needs some user uploaded data, you can use Amazon S3 to store the files, by using django-storages app to configure the correct Storage for you media files.

The configuration of django-storages is out of scope for this tutorial, but you can find some good tutorials on the web.


Share: