How to deploy a Django app on Heroku. Part I

This post is the first post of a series on how to deploy a Django project on Heroku.

You will see that the main idea behind these posts is not to build a functional Django app. Instead, what I want to do is to give you a bunch of good practices on how to build a Django app with different environments for testing, developing and production, useful packages installed, Internationalization and Localization properly configured, PosgreSQL installed, and much more.

PART I

This post explains how to create a Django project on Heroku. For this first part, I followed the tutorial Django on Heroku, and some ideas from the deploydjango website.

The topics covered here are:

  • set up Heroku
  • set up PostgreSQL
  • start a Django app in a Virtualenv
  • set the Procfile
  • specify the dependencies
  • separate your applications and your libraries
  • set the settings.py file
  • push your app in Heroku
  • change the name of your app

Set up Heroku

First of all, you need to set up a Heroku user account. It is free and instant.

Second, you need to have installed Python, Pip and Virtualenv on your computer.  See this post to find more information on how to install them on Mac OS X.

You need to install the Heroku Toolbelt on your local computer (your development environment). It gives you access to the Heroku command-line client (to create and manage Heroku apps), The Foreman (an easy option for running your apps locally), and Git (a revision control system).

Once installed, log in to Heroku from your command shell:

$ heroku login

If it is the first time you use Heroku, it will ask if you want to create a public key. Enter yes to generate one, you will need it to push code later on.

Set up PostgreSQL

In my case I have Mac OS X, Mountain Lion, and I used the Graphical Installer, recommended on the download page of PostgreSQL. It includes PostgreSQL, pgAdmin and the StackBuilder utility, for installation of additional packages.

During the installation process, you will need to set a password for the database superuser account (on Postgres).

Start a Django project in a Virtualenv

First, we need to create a directory for your project.

$ mkdir myfolderproject

$ cd myfolderproject

This directory will contain both the virtual environment and the Django application. We create the virtual environment with the flag –no-site-packages, which indicates that only the packages installed in the virtual environment will be used. If your version of Virtualenv is 1.7 or higher you can skip this flag, as it is the default behaviour.

$ virtualenv myenv –no-site-packages

$ source myenv/bin/activate

where the second line activates the virtual environment. Anytime, you can exit the virtual environment typing deactivate.

In order to install Django, we will use the django-toolbelt, which includes the following packages:

django

psycopg2

gunicorn (WSGI server)

dj-database-url (a Django configuration helper)

dj-static (a Django static file server)

With your virtual environment active:

$ pip install django-toolbelt

With Mac OS X, the package psycopg2 might give you an installation error. If you type

$ pg_config

hopefully it will give you a not found error (which means I can help you with this error…). You need to find the path of this command with

$ sudo find / -name pg_config

which should be something like /Library/PostgreSQL/9.3/bin. You need to add it to the $PATH variable, so open the .bash_profile file and add the line:

export PATH=/Library/PostgreSQL/9.3/bin:$PATH

Finally, restart your terminal and try again the installation. Hopefully it will work 😉

If you want to see which version of Django has been installed:

$ python

>>> import django

>>> print django.VERSION

which for me was Django 1.6.1.

Finally, let’s create the Django project:

$ django-admin.py startproject myproject .

The dot at the end indicates that the app will be installed without creating an additional folder.

Procfile

Procfile is a text file that declares the commands that will be run by your application dynos on the Heroku platform.

Create the file Procfile (you should not change this name) in the root directory of your app (at the same level where manage.py lives), and write:

web: gunicorn myapp.wsgi

You should be able to start your django app locally using the Procfile and Foreman, by typing:

$ foreman start

You will se something like

Listening at: http://0.0.0.0:5000 (1489)

Go to http://0.0.0.0:5000 with your web browser and check that you see the Django “It worked!” message. Type ctrl+c to exit.

Dependencies

Heroku recognizes Python applications by detecting a requirements.txt file in the root of a repository. This file, should contain the packages installed inside your virtual environment. You can create this file automatically using pip (you must be in your root directory, at the same level as your manage.py file):

$ pip freeze > requirements.txt

Having a top-level requirements.txt file is mandatory for Heroku. However, a best practice is to use separate .txt files to specify the dependencies needed for development and/or production.

At the same level of the requirements.txt we create a requirements folder that contains the packages used in any of these cases: development, production and testing (do not remove the requirements.txt file).

$ mkdir requirements

$ touch requirements/{common.txt,dev.txt,prod.txt,test.txt}

The file common.txt holds the dependencies that are shared between environments, like Django. The other .txt files should include the line

-r common.txt

followed by the packages needed for that environment. This line tells pip to include the dependencies in that file. Here, there are some examples of packages and the environment in which they usually belong:

Common: django, django-pagination, django-tastypie, South

Dev: django-debug-toolbar

Prod: gunicorn, psycopg2

Test: coverage, nose

The idea is to have different environments depending on if you want to run your code for development, production or testing. For example, the following line allows you to install all the development requirements:

$ pip install -r requirements/dev.txt

Finally, the requirements.txt file should contain:

-r requirements/prod.txt

If you want you can create two different environments, one for developing and one for testing, with the dependencies listed on dev.txt and test.txt. Remember to include them in your .gitignore file (see below).

Separating applications and libraries

Another good practice is to create two separate folders: apps and libs inside your myproject folder. The first one, apps, will contain all your applications that have models, views, etc. In the other one, we will include the applications that contain helper functionalities, that don’t belong to any of the other applications.

In order for these folders to be considered as packages by django, you must include an empty file on each of them called __init__.py

$ cd myproject

$ mkdir apps libs

$ touch apps/__init__.py libs/__init__.py

In order to create an app in each of these folders, first you must go inside it. For example:

$ cd myapp/apps

$ django-admin.py startapp myapp

However, we have to write the correct path when importing the apps of this folder. For example, inside the file myapp/views.py, we should import the model MyModel in the file myapp/models.py as:

from myproject.apps.myapp.models import MyModel

And also, you need to update your settings.py file to include the path of your new application:

INSTALLED_APPS = (
    …
    ‘myproject.apps.myapp’,
    …
)

Django settings

The next step is to configure the application for the Heroku environment. If you want a more advanced configuration of your settings.py file, taking into account the different environments (development, production, etc), go to the next section.

Open the settings.py, located in myprojectfolder/myproject. There are a few things you should do:

1. Change the following variables to:

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

ALLOWED_HOSTS = [‘yourappname.herokuapp.com’]

where yourappname.herokuapp.com is the URL of your project live on Heroku.

2. Write the following after the DATABASES declaration:

import dj_database_url

DATABASES[‘default’] = dj_database_url.config()

3. Add the following declaration at the end of the file:

SECURE_PROXY_SSL_HEADER = (‘HTTP_X_FORWARDED_PROTO’, ‘https’)

4. Add/modify the following to configure your static files:

STATIC_URL = ‘/static/’
STATIC_ROOT = ‘staticfiles’
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, ‘static’),
)

Finally, you have to change the file wsgi.py (which is loacated at the same folder than the settings.py file) to serve static files in production. Select the line:

application = get_wsgi_application()

and replace it with

from dj_static import Cling

application = Cling(get_wsgi_application())

Check out that your app is running with foreman start.

Git and Heroku

Once we have tested the application, we need to store the project in a Git repository. However, the myprojectfolder folder contains some extra files that we don’t want in our repository. Go inside the myprojectfolder, at the same level of the Procfile file and create the file .gitignore.

$ touch .gitignore

Open it and write:

myenv

*.pyc

myproject/ignore_directory

This indicates Git to ignore your virtual environment folder, all the compiled files created by python and an example of a directory to ignore, named ignore_directory. Feel free to change this file with the files or folders you want to ignore.

Then, we initialize a new Git repository and save our changes:

$ git init

$ git add .

$ git commit -m “First commit of my django app”

Next, we need to create a place to push to from Heroku:

$ heroku create appnameonheroku

and then push our application repository:

$ git push heroku master

If you get an error like Permission denied (publickey), is because you have to upload your public key to Heroku, see this post. Try

$ heroku keys:add ~/.ssh/id_rsa.pub

if you have a key, or just

$ heroku keys:add

if you want to create one.

Once you successfully push your repository on Heroku, you can visit your app with

$ heroku open

Also, ensure you have one dyno

$ heroku ps:scale web=1

Change the name of you app.

If you didn’t specify the name of your app, here appnameonheroku, it might have some name like simple-spring-9999 or murmuring-dawn-3477. If you go to the Heroku homepage, you can select your app and change its name. However, you have to update the git remote for the app, see this post:

$ git remote rm heroku

$ git remote add heroku git@heroku.com:yourappname.git

Note: if you have changed the name of your app, don’t forget to update the setting

ALLOWED_HOSTS.

More changes

Every time your make a change and want to upload it to Heroku, remember that you must type:

$ git add .

In case you want to delete the last command, type:

$ git reset

otherwise:

$ git commit -m “Describe your changes”

$ git push heroku master

Remember to be logged in to Heroku anytime you run these commands.

That’s all for today!

Hope it worked for you too 🙂

Do you want to go to the second part of this post?

How to set a Django app on Heroku. Part II.

Please, click on the g+1 if this post was useful 🙂

 

Google+TwitterLinkedInFacebookReddit

Please, add +Marina Mele in your comments. This way I will get a notification email and I will answer you as soon as possible! :-)