Stack: Python 3.12+ · Django 5.x · Django REST Framework · Linux Status: Mastered
Objectives
By the end of this lesson you will be able to:
- Install and isolate the stack's tools on Linux — and explain why isolation matters.
- Create a Django + DRF project with an enterprise-grade structure from minute one.
- Ship your first endpoint and verify it with
curl, reading the full response. - Initialize Git with a proper Python
.gitignore. - Know the course workflow: theory → exercises → feedback → project.
1. Installing the stack (Linux)
# Check your Python version (you need 3.12+)
python3 --version
# Create the project directory and an isolated virtual environment
mkdir -p ~/dev/ticketflow && cd ~/dev/ticketflow
python3 -m venv .venv
source .venv/bin/activate # your prompt will show (.venv)
# Install Django and DRF
pip install --upgrade pip
pip install django djangorestframework
# Freeze the dependencies (always, from the very beginning)
pip freeze > requirements.txtWhy
venv: every project has its own dependencies and versions. Without isolation, two projects fight over a library version. This is the seed of Lesson 27 (12-factor configuration). If you ever wonder "where should this dependency live?", the answer is: pinned inrequirements.txt, never global.
Tools we'll use later (install them now, take them easy):
sudo apt install postgresql redis-server # Modules 2 and 6 (DB and queues)
docker --version # Module 92. Creating the TicketFlow project
django-admin startproject config . # the dot matters!
python manage.py startapp eventsResulting structure (and the one we'll keep):
ticketflow/
├── config/ ← configuration (settings, urls, wsgi) — the "project"
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── events/ ← first app: events and capacity — the domain
│ ├── models.py
│ ├── views.py
│ └── ...
├── manage.py
└── requirements.txtEnterprise convention: we name the project
configbecause its only job is to configure and boot; the logic lives in apps. This avoids the classic confusingticketflow/ticketflow/layout. When a newcomer opens the repo, the structure itself explains the architecture: config at the edge, domain in apps.
Register DRF in config/settings.py:
INSTALLED_APPS = [
# ...default Django apps...
"rest_framework",
"events",
]3. Your first endpoint
Plain Django works with HttpRequest/HttpResponse; DRF adds Request/Response with content negotiation, serializers and auth. For an API, we'll live in DRF.
events/views.py:
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(["GET"])
def health(request):
"""Health endpoint: the first one of any serious backend."""
return Response({"status": "ok", "service": "ticketflow"})config/urls.py:
from django.contrib import admin
from django.urls import path
from events import views
urlpatterns = [
path("admin/", admin.site.urls),
path("api/health/", views.health),
]Boot the server and check:
python manage.py migrate # creates the initial DB (SQLite for now)
python manage.py runserver # http://127.0.0.1:8000curl -i http://127.0.0.1:8000/api/health/Expected output (note the headers — they're Lesson 01!):
HTTP/1.1 200 OK
Date: ...
Content-Type: application/json
...
{"status": "ok", "service": "ticketflow"}Go deeper: why is a health endpoint the first thing any serious backend ships? Because observability starts here: a load balancer (Lesson 02), a container orchestrator (Lesson 43) and your monitoring (Lesson 46) all ask this URL to decide whether your service is alive. Design it to check what actually matters — later it will hit the database too, and report degraded instead of dead.
4. Git from minute one
git initCreate .gitignore with this Python minimum:
__pycache__/
*.pyc
.venv/
db.sqlite3
.envgit add .
git commit -m "chore: initial TicketFlow project (Django + DRF)"Never commit
db.sqlite3or.env. Secrets live in environment variables (Lesson 27); the schema lives in migrations, not in the database file.
Lesson wrap-up
- [ ] Stack installed and venv working
- [ ] The
/api/health/endpoint answers 200 with JSON - [ ] Git repository initialized with
.gitignore - [ ] You can explain what
startappdoes vsstartproject
You're ready for Lesson 01 — HTTP in depth.