Deploying Django Apps to Heroku from GitHub

Introduction

Heroku is a popular Platform-as-a-Service (PaaS) that allows developers to run and deploy applications by availing the infrastructure required in terms of hardware and software.

This means that we do not have to invest in the hardware and software needed to expose our applications to end-users and this freedom allows us to concentrate on our business logic instead of deployment.

In this post, we will outline how to deploy a simple Django application to a Heroku pipeline. It targets existing Python developers and assumes a basic understanding of setting up and running a Django application.

Prerequisites

For this post, we'll need:

  • A free-tier Heroku account,
  • Python 3+ and Virtualenv installed
  • Git installed and a GitHub account.

Demo Application

Bootstrapping the Django App

Before deploying our Django application, we will need to prepare it as per Heroku's requirements. We will start by creating a virtual environment, activating it and installing the required packages, and finally bootstrapping a simple Django application:

$ virtualenv --python=python3 env --no-site-packages
$ source env/bin/activate
$ pip install django gunicorn
$ django-admin startproject plaindjango

If everything goes well, we should have the following landing page running on our local server:

django app bootstrap

At this point, the folder structure of our project is:

$ cd plaindjango && tree .
.
├── manage.py
└── plaindjango
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

1 directory, 6 files

Before we deploy to Heroku, we will need to make some changes. First, we need to change the ALLOWED_HOSTS setting in our plaindjango/settings.py to:

ALLOWED_HOSTS = ['*']

This setting defines the hosts or domains that our Django application can serve. It is a security measure against HTTP Header host attacks, but since ours is a simple demonstration project, we will allow all hosts by adding '*' in the list.

The next change we need to make is to specify a folder for our static files through the STATIC_ROOT setting:

STATIC_ROOT = os.path.join(BASE_DIR, 'static')

When Heroku is deploying our application, it runs the command django-admin collectstatic, which bundles and saves all static files in the specified folder. This folder will be in our project's root directory.

Preparing the App for Deployment

With our Django application ready, Heroku requires us to include the following files in our project root so that it can be ready for deployment:

  1. runtime.txt

The purpose of this file is to specify the Python version that will be used to run our project. In our case, the file will just contain:

python-3.7.6
  1. Procfile

This file specifies the commands to be executed when the program is starting up.

While setting up, we installed Gunicorn ('Green Unicorn') which is a pure-Python WSGI (Web Server Gateway Interface) server for UNIX.

While Django ships with its own WSGI server, our Profile will tell Heroku to use Gunicorn to serve our application. The contents of this file will be:

web: gunicorn plaindjango.wsgi:application --log-file -

This line tells Heroku that ours is a web process or application that will be started by using gunicorn. Gunicorn will then use the WSGI file of our project to start our application server.

  1. requirements.txt

Finally, we need the requirements.txt file that defines the requirements of our Django application. We can create this in our virtual environment by executing the following command:

$ pip freeze > requirements.txt

The final folder structure of our Django application containing the extra files will now be:

$ tree .
.
├── Procfile
├── manage.py
├── plaindjango
│   ├── __init__.py
│   ├── wsgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── requirements.txt
└── runtime.txt

1 directory, 9 files

With these files in place, our application is ready for Heroku.

Deploying to Heroku via GitHub

While Heroku offers its own Git platform that we can use for our deployments, it is not as feature-rich as GitHub. Heroku also allows us to pull our code from GitHub and deploy it.

Our code is ready for deployment, so we can go ahead and create a GitHub repository and push our code.

For reference, here is a sample Django application on GitHub that is ready for deployment on Heroku.

With our work ready on GitHub, let us head over to Heroku and create a new pipeline using the "New" button on the top right side of our Heroku dashboard.

We provide the name of our pipeline and the GitHub repository to connect to:

creating a django pipeline

A pipeline represents a group of Heroku applications that share the same codebase. In a pipeline, we can define different stages in a continuous delivery workflow.

This means that, through Heroku, we can deploy our code to our production, staging, and development environments at the same time, all from GitHub.

When using GitHub as the source of our application, we can configure Heroku pipelines to deploy code from different branches to different environments.

For instance, the code in our "master" branch will be deployed to the production environment, the "staging" branch to our staging environment and the "dev" branch to our development environment.

This gives us visibility over our project across multiple stages enhancing our delivery.

Heroku pipelines have a feature called "Review Apps" that allows us to deploy Pull Requests as standalone applications. With this enabled, we can verify the work in pull requests without having to pull the changes locally and testing them.

The Heroku Pipeline

This is the view of our recently created pipeline for our application on GitHub:

pipeline landing page

The pipeline has two stages by default and a section to enable review apps. Since all of our code currently resides on the "master" branch, let us go ahead and deploy the branch by clicking on "Add app" under the production stage:

creating the production app

Heroku allows us to add existing applications to a pipeline or create a new one. Since this is a new pipeline, we will create a new application called plaindjango-production that will be our production environment.

This results in:

ready production app

Our production application has been created but our code is not yet running. The next step is to choose the branch from which the code will be deployed to our production environment:

choose branch

Once we click on "Deploy", Heroku will pull our code from the "master" branch and deploy it. We can view the progress of the deployment by viewing the logs and once the application is deployed, we will receive a link to our running application:

successful logs

At the very end of the logs, there is a link to our running application. When we access the link, we are welcomed by our Django landing page:

production deployment

We have successfully deployed our production Django application to Heroku via GitHub. To create an app for our staging environment, the same steps are taken as for the master environment.

We will start by creating a "staging" branch on GitHub via the terminal:

$ git checkout -b staging && git push origin staging

Finally, an application is added to the project and a pull request is created from the "staging" branch to the "master" branch.

The pull request can be seen here on GitHub, and this is the result on our Heroku pipeline:

pull request deployed

We can see a new application has been created for our pull request and when we open it, we can see the changes that the pull request introduces to our project:

pull request changes live

Our pull request has been deployed successfully and we can review it before merging the changes into master. With automatic deployments activated, Heroku will deploy our changes once we merge the pull request into the master branch and the changes will go live automatically.

Conclusion

Our Django application has been deployed to Heroku from GitHub using a pipeline. While this is not the only way to deploy a Django application to Heroku, it the most suitable for a collaborative project.

Containerized applications can be deployed on Heroku by building Docker images and either publishing them to Dockerhub or Heroku's own container registry. More information about deploying Dockerized applications to Heroku can be found in the official documentation. Heroku also provides a Git platform that can be used to deploy applications in conjunction with their CLI tool.

With integration to git and GitHub's functionality to allow the deployment of containerized applications, Heroku is a capable platform to handle your development needs. The platform also provides add-ons through a marketplace.

These add-ons are services or pieces of infrastructure that can be used to enhance our applications. Such add-ons allow us to integrate our application to databases and datastores including PostgreSQL, MySQL, and Redis.

There is more to be achieved with Django applications on Heroku, and this post was meant to present a simple view into how to deploy a Django application to the platform in a way that suits our daily workflow.

The Heroku-ready Django project can be found here on GitHub as well as the open pull request that was also deployed.