// django · overview

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 Django — your hand-built stack, industrialized install & skeleton one venv, pip install django (6.1 ≈ 350k lines) startproject: settings, urls, wsgi/asgi, manage.py startapp: models, views, admin, migrations/ every generated file maps to a guide you did life of a request socket → gunicorn worker → wsgi.py callable 7 default middleware — the onion, written vertically urls.py scan → view(request, kwargs) ORM → SQL → template → HttpResponse → back out yours ↔ Django's App.__call__ ↔ get_wsgi_application() routes list ↔ urlpatterns view(environ, sid) ↔ view(request, sid) tiny filter() ↔ objects.filter() QuerySet Logging(GateKeeper(app)) ↔ MIDDLEWARE list the batteries you didn't build admin: free CRUD UI from model metadata auth: sessions + users + login_required migrations: schema generated from models defaults: CSRF token, SQL params, HTML escaping ON path from here official tutorial parts ↔ these guides read error pages top-down — you know every layer

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 — our GateKeeper middleware, grown up.
  • Migrations. makemigrations diffs your models against schema history and writes the CREATE TABLE/ALTER TABLE you were typing by hand in PostgreSQL 101; migrate applies 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 mysterywsgi.py is your callable, urls.py your route list, models.py your tiny ORM, settings.MIDDLEWARE your 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.
  • request is environ with luggage — pre-parsed GET/POST, an attached user; HttpResponse replaces hand-rolled start_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.