How to Deploy a Django Application to Heroku with Git CLI

Introduction

Heroku is a cloud platform that provides hosting services. It supports several programming languages including PHP, Node.js, and Python. It is Platform-as-a-Service (PaaS) which allows you to manage website applications while it takes care of your servers, networks, storage and other cloud components.

In this article, we'll take a look at how to deploy a Django application to Heroku, using Git.

You can follow the same steps, and deploy the application from GitHub, if it's hosted there.

Prerequisites

Below is a list of things that need to be done before we getting started with the deployment:

  • Git
  • Heroku Account and CLI
  • Django Application

The Heroku Command Line Interface (CLI) makes it easy to create and manage your Heroku applications directly from the terminal. It’s an essential part of using Heroku.

To install the Heroku CLI (a.k.a. Heroku Toolbelt), please follow the instructions on the official website.

Make sure your Django application is running on virtual environment which you need to keep active throughout the deployment process.

A Heroku Account

Once all these things have been installed, the next step is to create a free Heroku account here, if you don't have an account already.

After writing the following in a terminal:

$ heroku login

The terminal should display a message like:

heroku: Press any key to open up the browser to login or q to exit:

Press any key and log in using your browser. The terminal will then display a message along the lines of:

Logged in as [email protected]

Configure Django Application for Heroku

Now that we are done with the prerequisites, let's prepare our Django application for Heroku.

Procfile

A Procfile is a file named Procfile without any file extension placed in the root of your application. It lists the process types in an application and each process type is a declaration of a command that is executed when a container/dyno of that process type is started.

Before creating a Procfile, you'll want to install django gunicorn in your project directory:

$ pip install django gunicorn

While Django ships with its own WSGI server, our Procfile will tell Heroku to use Gunicorn to serve our application, which is also recommended by Heroku.

Now, create a Procfile in the parent directory and add the following line:

web: gunicorn yourdjangoweb.wsgi --log-file -

Replace yourdjangoweb with the actual name of your project.

Runtime.txt

Create a text file called runtime.txt in the same directory as the Procfile. It tells Heroku what version of Python your application is using. If you are not sure of the version, enter python --version in the terminal with your Django virtual environment activated.

Then add the version in runtime.txt:

python-x.x.x

See the supported versions of Python on Heroku here.

Allowed Hosts

This is an extra security measure in Django to prevent HTTP host header attacks by only allowing the site to be served at host/domains which are added in the ALLOWED_HOSTS list. If Debug = True and ALLOWED_HOSTS is [] then only localhost is allowed by default. To deploy and serve your web application on Heroku, add it to the list:

ALLOWED_HOSTS = ['herokuappname.herokuapp.com']

Alternatively, you can allow all apps from Heroku by omitting the app name like this:

ALLOWED_HOSTS = ['.herokuapp.com']

You can also use ['*'] to allow all hosts. You can find more details in the documentation.

Install Packages

Below are the extra packages which need to be installed in our virtual environment.

To connect our Django database with Heroku, install dj-database-url by calling:

$ pip install dj-database-url

As Heroku uses Postgres databases, we need its adapter for Python as well:

$ pip install psycog2

And finally, we will use WhiteNoise to serve static files in the production server. Which we can install by calling:

$ pip install whitenoise

We have already configured gunicorn, let's add a configuration for whitenoise and dj-database-url.

Configuring Static Files

First add basic settings to serve static files in any Django project. You can copy-paste the following settings in your settings.py:

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
PROJECT_ROOT   =   os.path.join(os.path.abspath(__file__))
STATIC_ROOT  =   os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'

# Extra lookup directories for collectstatic to find static files
STATICFILES_DIRS = (
    os.path.join(PROJECT_ROOT, 'static'),
)
  • Add WhiteNoise to the MIDDLEWARE list immediately after SecurityMiddleware which should be on the top:

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'whitenoise.middleware.WhiteNoiseMiddleware',
        
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
      ]
    
  • Add STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' in your settings.py.0

Configuring the Database

We are using dj-database-url to configure our database. Add these lines at the bottom of your settings.py:

import dj_database_url 
prod_db  =  dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(prod_db)

Requirements.txt

Heroku will recognize a deployed application as a Python application only if it has a requirements.txt file in the root directory. It tells Heroku what packages are required to run your application.

We can use pip freeze and pipe the output into a requirements.txt file for this:

$ pip freeze > requirements.txt

Your requirements.txt should include these:

whitenoise==5.2.0
dj-database-url==0.5.0
Django==3.0.9
gunicorn==20.0.4
psycopg2==2.8.5
pytz==2020.1

Note: The above versions are used by our Django application and they can differ for yours.

Connect Heroku Application With Git

Now we need to create a Heroku application:

$ heroku create herokuappname

It will display a "done" message with two URLs along this lines:

Creating ⬢ herokuappname... done
https://herokuappname.herokuapp.com/ | https://git.heroku.com/herokuappname.git

This means a Git repository has been created on Heroku cloud for your application. The URL https://herokuappname.herokuapp.com/ will be used to access your application anywhere but we still need to do one more step before running our application i.e. we need to push our code to the repository.

Initialize an empty repository in your project directory:

$ git init
> Initialized empty Git repository in /herokuappname/.git/

Connect your Heroku app with the empty git repository:

$ heroku git:remote -a herokuappname
> set git remote heroku to https://git.heroku.com/herokuappname.git

Add files to the staging area:

$ git add .

Commit the changes/files:

$ git commit -m "first commit for all files"

Finally, push the project to git repo hosted on Heroku:

$ git push master heroku

If everything goes fine, you will see an output like this:

Counting objects: 26, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (20/20), done.
Writing objects: 100% (26/26), 32.13 KiB | 0 bytes/s, done.
Total 26 (delta 1), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
.....
.....
remote: -----> Launching...
remote:        Released v1
remote:        https://herokuappname.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/herokuappname.git
[new branch]      master -> master

collectstatic Error

You might get an error related to collectstatic when you run git push heroku master command. This is related the to static files directory and you can bypass it with the following command:

$ heroku config:set     DISABLE_COLLECTSTATIC=1  
Setting DISABLE_COLLECTSTATIC and restarting ⬢ herokuappname... done, v2  
DISABLE_COLLECSTATIC: 1

It will tell Heroku not to run collectstatic command during application deployment. You can run it later using bower:

$ heroku run 'bower install --config.interactive=false;grunt prep;python manage.py collectstatic --noinput'

It can occur for many reasons including but not limited to:

  • Your STATICFILES_DIRS list is empty in settings.py or not configured properly.
  • Your static directory contains no files for git to track. You can add any temporary file to in your static directory to make it work.

Migrate the Database

Final step is to reflect your models to Heroku database by running migrations:

$ heroku run python manage.py migrate

That's it, your application is up and running on heroku! You can access it at [appname].herokuapp.com. The URL in our case would be http://herokuappname.herokuapp.com/.

Adding a Custom Domain Name

Every app on Heroku is hosted on .herokuapp.com but you can change it to your domain name if you own one. The process is simple:

heroku application list

  • Select Settings from navbar and scroll down to find the Domain section:

heroku domain settings

  • Click on Add domain where you will be able to add your domain name.

This option is for verified accounts only. You will be asked to enter credit card details on Heroku to verify your account. You can find more details about adding domains and subdomains on this page.

Conclusion

In this article, we deployed a Django application on Heroku with a custom domain name, using Git.

Besides various cloud services, Heroku also offers one of the best server up times and 24/7 operation and security team support.

Author image
Pakistan Twitter Website
I am a software engineer currently working on web/mobile app development. I try to make everyday count by learning or by teaching. Either way, I am learning. https://www.linkedin.com/in/abouthashir/