Week 3 — Django Setup & Docker Containerization
Goal: By the end of this handout, you will have a small Django app running locally, and then running inside a Docker container. Type every command yourself — don't copy-paste. Typing builds muscle memory.
Prerequisites
- Python 3.11+ installed (
python3 --version) - Docker Desktop (or Docker Engine) installed and running (
docker --version) - A terminal and a code editor
Part 1 — Set up your environment
Create a project folder and an isolated Python environment (a "virtual environment") so this project's packages don't collide with anything else on your machine.
mkdir mini-crm && cd mini-crm
python3 -m venv venv
# Activate it:
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
Your terminal prompt should now show (venv) at the start of the line. That means it's active.
Install Django:
pip install django
pip freeze > requirements.txt
Checkpoint: Open requirements.txt. You should see a line like Django==5.x.x. This file is what Docker will use later to install the same packages inside the container.
Part 2 — Create the Django project and app
django-admin startproject config .
python manage.py startapp contacts
Notice the . at the end of the first command — it creates the project files in the current folder instead of nesting them one level deeper.
Open config/settings.py and register the app you just created. Find INSTALLED_APPS and add "contacts":
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"contacts",
]
Checkpoint: Run python manage.py runserver and visit http://127.0.0.1:8000/. You should see Django's welcome page. Stop the server with Ctrl+C when you've confirmed it.
Part 3 — Build a minimal model, view, and template
We'll build a tiny contact list — one model, one view, one template.
contacts/models.py
from django.db import models
class Contact(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
company = models.CharField(max_length=100, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
contacts/admin.py
from django.contrib import admin
from .models import Contact
admin.site.register(Contact)
contacts/views.py
from django.shortcuts import render
from .models import Contact
def contact_list(request):
contacts = Contact.objects.all().order_by("name")
return render(request, "contacts/contact_list.html", {"contacts": contacts})
contacts/urls.py (create this file)
from django.urls import path
from . import views
urlpatterns = [
path("", views.contact_list, name="contact_list"),
]
config/urls.py — wire the app in
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
path("contacts/", include("contacts.urls")),
]
contacts/templates/contacts/contact_list.html (create the folders too)
<!DOCTYPE html>
<html>
<head><title>Contacts</title></head>
<body>
<h1>Contacts</h1>
<ul>
{% for contact in contacts %}
<li>{{ contact.name }} — {{ contact.email }} ({{ contact.company }})</li>
{% empty %}
<li>No contacts yet.</li>
{% endfor %}
</ul>
</body>
</html>
Now make and apply migrations, and create an admin login so you can add test data:
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
Checkpoint: Run python manage.py runserver, log into /admin/, add a contact or two, then visit /contacts/ and confirm they show up.
Part 4 — Containerize it with Docker
Stop the local server (Ctrl+C) — from here on, Docker will run it for you.
Dockerfile (in the project root, next to manage.py)
FROM python:3.11-slim
# Prevents Python from buffering stdout/stderr — logs show up immediately
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
.dockerignore — keeps junk out of the image
venv/
__pycache__/
*.pyc
db.sqlite3
.git/
Checkpoint — build the image:
docker build -t mini-crm .
Watch the output. Each RUN/COPY line becomes a "layer." If this fails, the error is almost always a missing or misspelled package in requirements.txt.
Run the container:
docker run -p 8000:8000 mini-crm
Visit http://127.0.0.1:8000/contacts/ again — it should look identical, but it's now being served from inside the container, not your local Python install.
Why the
-p 8000:8000? The left number is the port on your machine; the right is the port inside the container (matchingEXPOSE 8000). Docker forwards traffic between them.
Part 5 — (Optional but recommended) docker-compose
Typing that docker run command with all its flags gets old fast. docker-compose lets you define it once.
docker-compose.yml
services:
web:
build: .
ports:
- "8000:8000"
volumes:
- .:/app
command: python manage.py runserver 0.0.0.0:8000
The volumes line mounts your local folder into the container, so code changes show up without rebuilding the image.
docker compose up --build
Stop it with Ctrl+C, then docker compose down to clean up.
Exercises (do these on your own before wk4)
- Add a
phonefield to theContactmodel, make a migration, and confirm it shows up in the admin. - Add a second model (
Company) with aForeignKeyfromContacttoCompany, and update the template to show the company name. - Break something on purpose — misspell a package name in
requirements.txtand rebuild the image. Read the actual Docker error output. Fix it.
Troubleshooting cheat sheet
| Symptom | Likely cause |
|---|---|
| docker build fails on pip install | Typo or version conflict in requirements.txt |
| Page loads locally but not in container | Forgot 0.0.0.0:8000 (container defaults to localhost, which isn't reachable from outside) |
| Changes to code don't show up | No volume mount (Part 5), or you edited before rebuilding the image |
| port is already allocated | Something else is already using port 8000 — stop it, or map to a different host port, e.g. -p 8001:8000 |
What's next
Week 4 covers Git/GitHub fundamentals and a deeper Docker admin guide. Keep this mini-crm project — you'll push it to GitHub as your first repo.
Contents
- Week 3 — Django Setup & Docker Containerization
- Prerequisites
- Part 1 — Set up your environment
- Part 2 — Create the Django project and app
- Part 3 — Build a minimal model, view, and template
- Part 4 — Containerize it with Docker
- Part 5 — (Optional but recommended) docker-compose
- Exercises (do these on your own before wk4)
- Troubleshooting cheat sheet
- What's next
Pages Here
No sub-pages yet.
Page Info
Wiki: Program Training
Last edited on Sep 17, 2026 by Stuart Anderson
Maintainers
| Editor | Last Activity |
|---|---|
| Stuart Anderson creator | Sep 17, 2026 |