In this tutorial, you will learn to create a simple Django app and deploy it on Heroku. At last, you will learn to use GitHub actions to create a workflow to auto-deploy the app every time you push a new change in your main branch.

Pre-requisites for this tutorial

You can refer to the repository used in this tutorial.

What is GitHub action?

GitHub action is a Platform to automate developer workflow. But what are these workflows? The workflow involves coding, building, testing, releasing, and deploying a project. In development, all big projects have their workflow and Github action helps in automating these workflows with the help of world-class CI/CD.

What is the CI/CD pipeline?

CI/CD stands for continuous integration and continuous deployment or continuous delivery.

CI is a development process where the team members integrate their work in the shared repository using some version control like git. When the code is pushed into a repository on Github it is put under several automated tests.

So every time someone from the team pushed into the master branch the code goes through this workflow. After the CI process, Every change that passes through automation tests is deployed to production automatically. This helps in fast execution while not compromising the quality of the production.

Setting up the Heroku account

Next, set up a Heroku account. Once you are signed up on Heroku, download Heroku CLI from here. Make sure you have git installed on your system before installing Heroku CLI.

Once you are done with installing Heroku CLI. Go to your terminal and run

heroku --version

If the installation of Heroku CLI is done it will show you the version of the same.

Now, the first thing you need to do is login into your Heroku account through your command line. To do this type :

heroku login

It will ask you to type any key to continue. Press a key and you will be redirected to a page like this, login in to your Heroku account.

Once you are authenticated you can continue with your deployment. Now let's first create our app on Heroku. To create an app you need to type the below command on your command line.

heroku create "NAME OF YOUR APP"

Now type heroku open

It will open the URL for your created app on your default browser. But you haven't deployed anything yet. So you will Heroku's default webpage. Now let's create a simple Django app and configure it so that you can deploy it on Heroku.

Creating a simple Django app

It's time to make a simple Django app that can be deployed on Heroku and later GitHub actions will be used to auto-deploy it. To deploy the app on Heroku you need to configure some files.

First, you need to add a file named requirements.txt in your root directory. You can copy the content of requirements.txt from here.

Now install the requirements using pip install -r requirements.txt.

[Optional] If you work with virtual environment. Follow this tutorial.

Now, add a file called Procfile in your root directory. This file has no extension and is case-sensitive. Do make sure that the name has a capital 'P' in it. In this file, the web process and entry points are declared.

Open the Procfile and add the following line to it:

web: gunicorn djangoprojectname.wsgi

Here web is the process type; gunicorn is the command needed to run the web process. Gunicorn helps to communicate python code with the web servers and it takes the help of the WSGI file inside the project to do that.

Note: Put your own Django project name in place of 'djangoprojectname'.

Go to your project settings.py file and add a line to tell Heroku where to look for static files.

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

You can manage static files of the project using a python library called whitenoise. It should be already installed from the requirements.txt file.

Add it to the middleware list in your settings.py.. The middleware should be below your django.middleware.security.SecurityMiddleware middleware and above all the other middleware.

'whitenoise.middleware.WhiteNoiseMiddleware'

Now, in your settings.py add the Heroku app domain you created above in your allowed host and set DEBUG to False.

When we are in development we want the DEBUG to be true to know the error and its traceback which comes in handy in debugging. But in production, this could help other people to find vulnerabilities in our site and we definitely do not want that.

[Optional] python-decouple: Manage Environment Variables In Django

Next, you need to store the secret key in a variable in your Heroku app settings. To do that open your Heroku account -> your app -> settings. Then click on Config vars.

Here give a name to your variable and paste the value of the secret key from your settings.py to the value field.

Now, in your settings.py set your secret key as follows:

SECRET_KEY = os.environ['SECRET_KEY']

Lastly, add a .gitignore file in your root directory. This file contains files that you intentionally do not want git to track. We are done with all the configurations now and our Django app is ready for deployment.

Deployment on Heroku

First, commit your changes.

  • Open your terminal at the root directory of project.
  • Run git init to initialize a new git repository.
  • Add files to the staging area using git add -A
  • Commit the files that are in the staging area using git commit -m "first version of site"

Now it is time to deploy.

git push heroku master

It pushes the app to the Heroku repository and runs the site after uploading the app.

Creating continuous deployment

Now, for continuous deployment, you need a GitHub account. Create a new repository on GitHub and push your changes to github.

  • Open your terminal at the root of the project.
  • Create a new branch named main using git branch -b main
  • Set the origin to the repository URL using git remote add origin "url of your github repository"
  • Push the changes to main branch using git push -u origin main

This will push the Django project to the remote GitHub repository.

Now, in the project's root directory create a directory called .github, and inside that create another directory called workflows. Inside the workflow create a file called django.yml.

Now, let's write the workflow to auto-deploy any change that is made in the project. Before that let's first understand the few terminologies related to the flow

  • Events: An event is an activity that triggers our workflow. Like we can assign our workflow to trigger every time we push something in the main branch.
  • Jobs: Each workflow is made up of several jobs. A job further is a combination of several steps.
  • Steps: Steps are commands or actions that we want to execute in the runner.
  • Runner: A runner is a machine installed with GitHub Actions runner applications. The jobs we create are run on these servers and each job runs on a new virtual environment. These runners listen to a job from the workflow, run them, and then send the progress or results back to Github.
  • Actions: Actions are the smallest building block of a workflow. These are commands that are combined with steps to create a job. Now, since you are now a little bit familiar with some basic terminologies, copy the following code in your django.yml file.
name: CD

# Controls when the workflow will run
on:
  # Triggers the workflow on push request events but only for the main branch
  push:
    branches: [ main ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Runs a single command using the runners shell
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: 3.7

      - name: Install Dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

  deploy:
    name: Deploy to Heroku
    # The type of runner that the job will run on
    runs-on: ubuntu-latest
    needs: build

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps: 
      - uses: actions/checkout@v2
      - uses: akhileshns/heroku-deploy@v3.12.12 # This is the action
        with:
          heroku_api_key: ${{secrets.HEROKU_API_KEY}}
          heroku_app_name: ${{secrets.HEROKU_APP}} #Must be unique in Heroku
          heroku_email: ${{secrets.HEROKU_EMAIL}}
      - name: Deployed successfully
        run: |
          echo Deployed!!

Let's try to understand what is happening in this workflow.

The first line is the name of the workflow CD.

The on keyword declares events that will trigger this workflow. Here the workflow will be triggered on a push request but only for the main branch.

A workflow run is made up of one or more jobs.

Jobs define what to do when a particular event is been triggered. You can think of it collection of tasks that need to be performed when a particular event is triggered. Here we have two jobs in our workflow build and deploy.

Let's understand the jobs mentioned in the file.

build The first job we have in our workflow is 'build'. It runs on an Ubuntu operating system. The keyword uses tells the job to retrieve version2 of the action actions/checkout/@v2. This action checks out and downloads the repository to the runner; the runner is ubuntu which is defined in runs-on attribute.

The next step or action in our job uses the actions/[email protected] action to install the specified version of the python in our environment.

The run keyword executes a command on the runner. Here few commands are used to upgrade pip and install packages from the requirements file

deploy After build is executed successfully the second job in the workflow will run. It is the deploy job. It also runs on Ubuntu operating system and it needs the build job. If the build job fails to execute, the deploy job will not run.

In the deploy job, you will again have to use pre-defined action to check out the repository under $GITHUB_WORKSPACE, so the workflow can access it. akhileshns/[email protected] action is used which helps in deploying the repository to Heroku.

To deploy the app to Heroku you need Heroku credentials to log in. But it cannot public. So you need to create a Heroku API token and use it to log in to your Heroku account through actions. To generate the token use the following Heroku command

heroku authorizations:create

Now, you can put this in your workflow directly but your GitHub repository can be public and you do not want to expose it in public. So the way to put this in our GitHub is through GitHub secrets.

Go to your project repository and click on settings -> secrets. Click on new repository secrets and now give your secret a name and value. By now you should be ready to use it in your GitHub actions workflow.

Tip: Similarly, you can also create secrets for your app name and email.

Now, the workflow part is complete. Push the YAML file to your GitHub repository.

git commit -am "added YAML file" 
git push origin main

Now, let's update some files in the local repository and push them to the GitHub repository and check whether the auto-deploy is working or not.

Change your home.html in your templates as follows

{% extends 'blog/base.html' %}
{% block content%}
    <h1>Blog home</h1>
    <div class="jumbotron">
        <h2>Blog 1</h2>
        <strong>By xyz</strong>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
        sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
        Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
        Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

        <h2>Blog 2</h2>
        <strong>By xyz</strong>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
        sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
        Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
        Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
        Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    <div>
{% endblock content %}

Again, add and commit the new changes and push them into your GitHub repository. Once your workflow is executed successfully. Then go to your Heroku app URL and check whether your app is auto-deployed or not.

That's all. If you find this useful do subscribe to the free python newsletter.