Containerising a simple Django application

Rajesh GurajalaRajesh Gurajala
7 min read

In this article, we'll take you on a hands-on journey to containerize a Django application from scratch. Whether you're new to Django or Docker, we'll break down everything β€” from understanding the core structure of a Django project to building your own Docker image and running your app inside a container. Let’s turn your Django project into a portable, production-ready container β€” step by step!

1) Understanding the basics of a django project :

  1. Install python, django in ur terminal.

  2. And then run the following commands:

django-admin startproject myproject
cd myproject
  1. This will create myproject folder and the structure of myproject looks like:

πŸ”§ STRUCTURE :

myproject/
β”œβ”€β”€ manage.py
β”œβ”€β”€ myproject/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ settings.py
β”‚   β”œβ”€β”€ urls.py
β”‚   β”œβ”€β”€ asgi.py
β”‚   └── wsgi.py
  1. Now lets explore all components in myproject / myproject folder:

Project Folder: myproject/

This contains global settings for the project.

a. __init__.py

  • Makes this folder a Python package.

b. settings.py

  • Contains project-wide settings:

    • INSTALLED_APPS: List of all Django apps.

    • DATABASES: DB connection info.

    • MIDDLEWARE: Middleware stack.

    • TEMPLATES: Template engine config.

    • STATIC_URL, MEDIA_URL: For static/media files.

c. urls.py

  • Main URL configuration file.

  • You route URLs to views here.

  • Can include app-level URLs:

      path('myapp/', include('myapp.urls'))
    

d. asgi.py & wsgi.py

  • Entry points for deployment:

    • wsgi.py is used by WSGI servers like Gunicorn.

    • asgi.py is for ASGI servers like Daphne or Uvicorn (async support).

Now we came to know that myproject / myproject folder is just a settings folder. The actual logic of applications lies in their app folders.

  1. Now in the myproject/ folder to create a app folder with the name myapp/, run this command:
python manage.py startapp myapp

Now the folder structure will be:

πŸ”§ STRUCTURE

myproject/
β”œβ”€β”€ manage.py
β”œβ”€β”€ myproject/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ settings.py
β”‚   β”œβ”€β”€ urls.py
β”‚   β”œβ”€β”€ asgi.py
β”‚   └── wsgi.py
β”œβ”€β”€ myapp/
β”‚   β”œβ”€β”€ admin.py
β”‚   β”œβ”€β”€ apps.py
β”‚   β”œβ”€β”€ migrations/
β”‚   β”œβ”€β”€ models.py
β”‚   β”œβ”€β”€ tests.py
β”‚   β”œβ”€β”€ views.py
β”‚   β”œβ”€β”€ urls.py
β”‚   β”œβ”€β”€ forms.py (optional)
β”‚   └── templates/
β”‚       └── myapp/
β”‚           └── example.html

myapp/ is the folder containing the actual application logic.

  1. The general components in any application folder are:

πŸ”ΉApp Folder: myapp/

This is where your application logic lives.

a. admin.py

  • Registers models to Django admin panel.

b. apps.py

  • App configuration class.

c. migrations/

  • Auto-generated DB migration files.

  • Contains __init__.py and numbered migrations like 0001_initial.py.

d. models.py

  • Defines database models.

  • Example:

      class Student(models.Model):
          name = models.CharField(max_length=100)
    

e. views.py

  • Handles request and response.

  • View functions or class-based views:

      def home(request):
          return render(request, 'myapp/home.html')
    
  • App-specific URL patterns.

      from django.urls import path
      from . import views
    
      urlpatterns = [
          path('', views.home, name='home')
      ]
    

πŸ”Ή 4. templates/ and static/

  • Place these outside the app or inside each app.

a. templates/

  • HTML files rendered by views.

  • Follow this structure:

      templates/
      └── myapp/
          └── home.html
    
  • Use {% extends "base.html" %} and {% block content %} to create reusable templates.

b. static/

  • For CSS, JS, images, etc.

      static/
      └── myapp/
          β”œβ”€β”€ style.css
          └── script.js
    

Add these in settings.py:

STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / "static"]

βœ… Best Practice Structure:

myproject/
β”œβ”€β”€ manage.py
β”œβ”€β”€ myproject/
β”‚   └── settings/
β”‚       β”œβ”€β”€ __init__.py
β”‚       β”œβ”€β”€ base.py
β”‚       β”œβ”€β”€ dev.py
β”‚       └── prod.py
β”œβ”€β”€ myapp/
β”‚   β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ views/
β”‚   β”œβ”€β”€ urls.py
β”‚   β”œβ”€β”€ forms/
β”‚   β”œβ”€β”€ templates/
β”‚   └── static/
β”œβ”€β”€ templates/
β”‚   └── base.html
β”œβ”€β”€ static/
β”‚   β”œβ”€β”€ css/
β”‚   β”œβ”€β”€ js/
β”‚   └── images/
└── requirements.txt

🧠 Summary

PartPurpose
manage.pyEntry point for Django commands
settings.pyAll configurations: DB, static, apps, middleware
urls.pyURL routing
models.pyDefine DB schema
views.pyDefine logic for HTTP requests
templates/Frontend HTML
static/Frontend CSS/JS/Images
migrations/DB schema versioning

βœ… 1. Real-world projects usually have multiple apps

Example:

Suppose you're building an e-commerce website, you might split features into multiple apps like:

myproject/
β”œβ”€β”€ users/           # login, registration, profiles
β”œβ”€β”€ products/        # product listings, details
β”œβ”€β”€ cart/            # shopping cart
β”œβ”€β”€ orders/          # order history, payment
β”œβ”€β”€ reviews/         # product reviews and ratings
β”œβ”€β”€ myproject/       # main project settings and URLs
└── manage.py

Each app is a self-contained component responsible for a specific domain of the project.

βœ… 2. How to run all these apps ?

manage.py remains your central command-line tool even with multiple apps.

When you run:

python manage.py runserver
  • Django loads all apps listed in INSTALLED_APPS (defined in settings.py).

  • All migrations, views, URLs, models, templates, etc., from each app are registered and active.

Example:

# settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'users',
    'products',
    'cart',
    'orders',
    'reviews',
]

Once listed here, Django manages them together using manage.py.

βœ… 3. No matter how many apps you have, single manage.py = All apps run together.

🎯 Sample Project: myshop

We'll create 3 apps:

  • users/ β†’ login, register, profile

  • products/ β†’ product list/detail

  • orders/ β†’ order history, checkout


πŸ—‚οΈ Folder Structure

myshop/
β”œβ”€β”€ manage.py
β”œβ”€β”€ myshop/                # Project settings
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ settings.py
β”‚   β”œβ”€β”€ urls.py            # Main URL config
β”‚   └── wsgi.py
β”œβ”€β”€ users/                 # App 1
β”‚   β”œβ”€β”€ admin.py
β”‚   β”œβ”€β”€ apps.py
β”‚   β”œβ”€β”€ models.py
β”‚   β”œβ”€β”€ urls.py            # App-specific URLs
β”‚   β”œβ”€β”€ views.py
β”‚   └── templates/users/
β”œβ”€β”€ products/              # App 2
β”‚   β”œβ”€β”€ admin.py
β”‚   β”œβ”€β”€ apps.py
β”‚   β”œβ”€β”€ models.py
β”‚   β”œβ”€β”€ urls.py
β”‚   β”œβ”€β”€ views.py
β”‚   └── templates/products/
β”œβ”€β”€ orders/                # App 3
β”‚   β”œβ”€β”€ admin.py
β”‚   β”œβ”€β”€ apps.py
β”‚   β”œβ”€β”€ models.py
β”‚   β”œβ”€β”€ urls.py
β”‚   β”œβ”€β”€ views.py
β”‚   └── templates/orders/
└── static/

βš™οΈ Step-by-step Setup

βœ… 1. In settings.py, add all apps

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    # your custom apps
    'users',
    'products',
    'orders',
]

βœ… 2. myshop/urls.py β†’ Main URL router

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users/', include('users.urls')),
    path('products/', include('products.urls')),
    path('orders/', include('orders.urls')),
]

βœ… 3. Each app has its own urls.py

πŸ“ users/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('login/', views.login_view, name='login'),
    path('register/', views.register_view, name='register'),
]

πŸ“ products/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.product_list, name='product_list'),
    path('<int:product_id>/', views.product_detail, name='product_detail'),
]

πŸ“ orders/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('checkout/', views.checkout_view, name='checkout'),
    path('history/', views.order_history, name='order_history'),
]

βœ… 4. Sample Views

products/views.py

from django.shortcuts import render

def product_list(request):
    return render(request, 'products/list.html')

def product_detail(request, product_id):
    return render(request, 'products/detail.html')

πŸš€ How Django maps URLs now:

URLMapped to
/products/products.views.product_list()
/products/5/products.views.product_detail()
/users/login/users.views.login_view()
/orders/checkout/orders.views.checkout_view()

βœ… Key Benefits

FeatureResult
Modular URL routingEasy to scale and organize routes
Per-app templatesKeeps frontend code modular
Shared settings & runOne manage.py handles all apps
Clean separationEasier for teams and maintenance

As we understood about the folder structure of django, now lets dive into containerisation.

2) Containerising the application :

0) For complete basics on docker, https://github.com/iam-veeramalla/Docker-Zero-to-Hero/blob/main/README.md

i) Installing docker:

sudo apt update
sudo apt install docker.io -y
sudo usermod -aG docker ubuntu

ii) Installing source code and docker file from a github repo:

git clone https://github.com/iam-veeramalla/Docker-Zero-to-Hero.git
cd Docker-Zero-to-Hero/examples/python-web-app
ls

We can see Dockerfile, source code folder and requirements.txt file

iii) With the dockerfile, build an image with docker build . command.

iv) With docker images command, u can see our newly created image with its id, size.

v) Now run the container with docker run -p 8000:8000 -it <image-id>

We can see that the container is running.

11
Subscribe to my newsletter

Read articles from Rajesh Gurajala directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Rajesh Gurajala
Rajesh Gurajala