How Django works: the framework you already built
You've built every piece of Django by hand across these guides — a WSGI callable, a route table, middleware, an ORM, templates, CSRF defense. This overview assembles the map: the startproject skeleton file by file, the full life of a request through the framework, and a side-by-side of your ~150 lines against Django's modules. Two simulators run the pipeline and the correspondence.
mindmap — quick refresh
Prerequisites: this is the capstone — it assembles WSGI, the tiny ORM, HTML forms & CSRF, SSR, packaging, and OOP. Have at least WSGI and the ORM under your belt. Time: ~40 minutes reading, then the official tutorial.
Django is ~350,000 lines of Python, twenty years old (2005, named after guitarist Django Reinhardt), and runs Instagram. It is also — and this is the claim these guides have been quietly proving — a framework you have already built. A WSGI callable, a route table, a middleware onion, a self-describing ORM, template rendering, CSRF tokens: you wrote each one small. What Django adds is not new kinds of machinery; it's the same machinery industrialized, with twenty years of edge cases handled. So this guide is not a tutorial — the official one is excellent — it's the map that stops Django from ever feeling like magic.
Install and read the skeleton
Setup is the packaging workflow, verbatim:
python3 -m venv .venv && source .venv/bin/activate
pip install django # 6.1 at the time of writing
django-admin startproject foodsite
cd foodsite && python manage.py startapp orders
That generates a tree, and here's the point of this whole article — annotate it with where you've been:
foodsite/
├── manage.py ← runs commands inside your venv'd project
├── foodsite/ ← the project: plumbing
│ ├── settings.py ← config: MIDDLEWARE list, DATABASES, apps
│ ├── urls.py ← the route table → How WSGI works
│ ├── wsgi.py ← the WSGI callable → How WSGI works
│ └── asgi.py ← its async sibling → (same guide, last section)
└── orders/ ← an app: your actual features
├── models.py ← classes ↔ tables → How ORMs work
├── views.py ← request → response → SSR labs, WSGI
├── admin.py ← free CRUD UI → (new! see below)
├── migrations/ ← schema history → (new! see below)
└── tests.py
Open wsgi.py and enjoy the punchline — after the comments it's two meaningful lines, ending in application = get_wsgi_application(). The entire framework is inside a callable with the exact signature you implemented from scratch. Gunicorn cannot tell your 40-line framework and Django apart, because there is nothing to tell apart.
The life of a request
Everything Django does happens inside one application(environ, start_response) call — so let's trace GET /students/42/ through the whole machine, station by station. You built every station; Django's contribution is the assembly. The seven middleware in a fresh settings.py are your onion written vertically — SecurityMiddleware, SessionMiddleware, CommonMiddleware, CsrfViewMiddleware, AuthenticationMiddleware, MessageMiddleware, XFrameOptionsMiddleware — request descending, response climbing, any layer able to short-circuit (that's CSRF rejection happening before your view ever runs):
Note what the trace makes obvious: a Django "view" is your WSGI view with better luggage — request is environ upgraded to an object (request.GET, request.POST pre-parsed, request.user attached by the auth middleware), and returning an HttpResponse replaces calling start_response by hand.
Yours ↔ Django's, line by line
The correspondence deserves to be exact, not hand-waved. Left column: code you have actually written in these guides. Right: the Django file where the same job lives:
Written out once, view-layer included:
# you wrote (tinyorm + framework.py): # Django (models.py / views.py / urls.py):
class Student(Model): class Student(models.Model):
name: str name = models.CharField(max_length=100)
course: str course = models.CharField(max_length=100)
Student.filter(course="AI") Student.objects.filter(course="AI")
@app.route(r"/students/(?P<sid>\d+)/") path("students/<int:sid>/", views.detail)
def detail(environ, sid): def detail(request, sid):
return "200 OK", f"<h1>…{sid}</h1>" s = Student.objects.get(pk=sid)
return render(request, "detail.html", {"s": s})
Differences worth respecting: Django's fields carry database detail (CharField(max_length=100)) because migrations generate real DDL from them; objects.filter() returns a lazy QuerySet (SQL runs on iteration, not on the call — the big upgrade over our eager tiny ORM); and render() is the SSR template merge with auto-escaping on by default.
The batteries you didn't build
Four additions have no counterpart in your hand-built stack — these are what you're actually adopting Django for:
- The admin. Two lines in
admin.py(admin.site.register(Student)) and Django serves a full create/read/update/delete UI for your models — generated from the same self-description your tiny ORM introspected. This is the killer feature that made Django famous in newsrooms. - Auth, complete. The session machinery from authentication vs authorization plus users, groups, password hashing, and
@login_required— ourGateKeepermiddleware, grown up. - Migrations.
makemigrationsdiffs your models against schema history and writes theCREATE TABLE/ALTER TABLEyou were typing by hand in PostgreSQL 101;migrateapplies them in order, on any machine. - Secure defaults, stacked. Values through SQL placeholders (ORM guide), CSRF tokens checked by middleware (forms guide), template auto-escaping (SSR part 1's warning, made default), clickjacking and HTTPS headers. Django's philosophy: the safe path is the default path.
Your path from here
Do the official Django tutorial next — it will feel like revision, and that's the intended effect. Part 1 (project setup) is the WSGI + packaging guides; part 2 (models, admin) is the ORM guide plus the free UI; part 3 (views, URLconfs) is the framework you wrote; part 4 (forms) is the forms guide with csrf_token finally explained by mechanism, not incantation. And when something breaks, read the error page top-down without fear: every frame in that traceback — middleware, URL resolver, view, ORM — is a layer you have built with your own hands.
Takeaways
- Django is your stack, industrialized — WSGI callable, route table, middleware onion, self-describing ORM, template merge: nothing in the core is a new kind of thing.
- The skeleton is a map, not a mystery —
wsgi.pyis your callable,urls.pyyour route list,models.pyyour tiny ORM,settings.MIDDLEWAREyour onion written vertically. - A request crosses ~7 middleware, one URLconf, one view — and can be short-circuited early (CSRF, auth) exactly like your
GateKeeper; responses climb back out through every layer. requestisenvironwith luggage — pre-parsed GET/POST, an attacheduser;HttpResponsereplaces hand-rolledstart_response.- Adopt Django for the batteries — admin, auth, migrations, lazy QuerySets, and safe-by-default settings are the 350k lines you shouldn't rewrite.
- Debug fearlessly — every layer in a Django traceback is one you've built small; read top-down and name the station.
References
- Django Software Foundation. (n.d.). Django at a glance (Django documentation). Retrieved August 17, 2026, from https://docs.djangoproject.com/en/stable/intro/overview/
- Django Software Foundation. (n.d.). Design philosophies (Django documentation). Retrieved August 17, 2026, from https://docs.djangoproject.com/en/stable/misc/design-philosophies/
- Django Software Foundation. (n.d.). FAQ: General (Django documentation). Retrieved August 17, 2026, from https://docs.djangoproject.com/en/stable/faq/general/
- Django Software Foundation. (n.d.). Writing your first Django app, part 1 (Django documentation). Retrieved August 17, 2026, from https://docs.djangoproject.com/en/stable/intro/tutorial01/
- Holovaty, A., & Kaplan-Moss, J. (2009). The definitive guide to Django: Web development done right (2nd ed.). Apress.