Dockerizing a Python Django Web Application

  • Understand what Docker is and how it is used,
  • Build a simple Python Django application, and
  • Create a simple Dockerfile to build a container running a Django web application server.
  • Setup a Continuous Integration and Delivery (CI/CD) pipelines to build and test the Docker image automatically

What is Docker, Anyway?

  • Docker doesn’t require the often time-consuming process of installing an entire OS to a virtual machine such as VirtualBox or VMWare.
  • You create a container with a few commands and then execute your applications on it via the Dockerfile.
  • Docker manages the majority of the operating system virtualization for you, so you can get on with writing applications and shipping them as you require in the container you have built.
  • Dockerfiles can be shared for others to build containers and extend the instructions within them by basing their container image on top of an existing one.
  • The containers are also highly portable and will run in the same manner regardless of the host OS they are executed on. Portability is a massive plus side of Docker.


Setting Up a Django web application

  • Clone the repository to your local machine.
├── requirements.txt # < Python module list
└── martor_demo # < Django Project root
├── app # < App code
│ ├──
│ ├──
│ ├──
│ ├── migrations
│ ├──
│ ├── templates
│ ├──
│ └──
├── # < Django management tool
└── martor_demo # < Django main settings
$ python -m venv venv
$ echo venv/ >> .gitignore
$ source venv/bin/activate
  • Gunicorn: gunicorn is an HTTP server. We’ll use it to serve the application inside the Docker container.
  • Martor: Martor is Markdown plugin for Django
$ echo martor >> requirements.txt
$ echo gunicorn >> requirements.txt
$ pip install -r requirements.txt
$ git add .gitignore requirements.txt
$ git commit -m "added martor and gunicorn"
$ git push origin master
$ cd martor_demo
$ python runserver
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python migrate' to apply them.
$ python makemigrations
$ python migrate

Testing in Django

# app/

from django.test import TestCase
from app.models import Post

class PostTestCase(TestCase):
def testPost(self):
post = Post(title="My Title", description="Blurb", wiki="Post Body")
self.assertEqual(post.title, "My Title")
self.assertEqual(post.description, "Blurb")
self.assertEqual(, "Post Body")
  • Import the Post model from the application.
  • Create a post object with some initial values.
  • Check that the values match expectations.
$ python test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
Ran 1 test in 0.001s

Destroying test database for alias 'default'...
$ python check --deploy

Static vs Dynamic Files

  • Edit the file martor_demo/
  • Locate the STATIC_ROOT and MEDIA_ROOT variables and replace the lines with these:
# martor_demo/

. . .

STATIC_ROOT = os.path.join(BASE_DIR, "static")
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
$ python collectstatic

Style checker

$ pip install flake8
$ flake8 . --max-line-length=127

Continuous Integration

$ git add martor_demo/ app/
$ git add static
$ git commit -m "add unit test and static files"
$ git push origin master
  • Visit Semaphore and sign up for a free account using the Sign up with GitHubbutton.
  • Use the + (plus sign) button next to Projects to find your GitHub repository:
  • Click on Choose next to your repository:
  • Click on Continue to workflow setup.
  • Select the single job templante and click on Customize it first
  • Pipeline: a pipeline is made of blocks that are executed from left to right. Pipelines usually have a specific goal such as building and testing code.
  • Block: blocks group jobs that can be executed in parallel. Jobs in a block usually have similar commands and configurations. Once all job in a block complete, the next block begins.
  • Job: jobs define the commands that do the work. They inherit their configuration from the parent block.
  • Promotions: We can define multiple pipelines and connect them with promotions to get complex multi-stage workflows.
  • Click on the first block and set its name to “Build”
  • On the job commands block type the following:
sem-version python 3.9
mkdir .pip_cache
cache restore
pip install --cache-dir .pip_cache -r requirements.txt
cache store
  • Click on Run the Workflow.
  • Set the branch to master.
  • Click on Start.
  • sem-version activates a specific version of one of the supported languages. In the case of Python, it also setups a virtual environment.
  • checkout uses git to clone correct code revision.
  • cache stores and restores files in the project-wide cache. Cache can figure out which files and directories it needs to keep. We can use it to avoid having to download Python packages each time.
  1. Click on Edit Workflow.
  2. Click on + Add Block.
  3. Set the name of the block to “Test”.
  4. Open the Prologue section, type the following commands. The prologue is executed before each job in the block:
sem-version python 3.9
cache restore
pip install --cache-dir .pip_cache -r requirements.txt
cd martor_demo
python makemigrations
python migrate
python test
  1. Add a second job called “Checklist” and add the following commands:
cd martor_demo
python check --deploy
  1. This is a good place to add some style checking. Add a third job called “Style check” with the following commands. We’re using flake8 to check the style of the code:
pip install flake8
flake8 martor_demo/ --max-line-length=127




Supporting developers with insights and tutorials on delivering good software. ·

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Proprietary Vs. Open Source CMS: Which Is The Right Choice For You?

The Pair Programming Dovetail: Code and Congruence.

Everyone must know about Selenium

AWS Pricing: A Quick Guide

Why A VP Decided to Get Cloud Certified

Enhance your SEO with Drupal Semantic Web

Cloud Data Warehouse

A Raspberry Pi Hexy

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store


Supporting developers with insights and tutorials on delivering good software. ·

More from Medium

Debugging a Django Application with PyCharm Community

Screenshot from 2022-05-12 16-07-13.png


Introduction to Django Framework

How to check if a field of a model is changed in Django?