Part 7 · 2 chapters · ~12 min
Django Internals
Settings and app loading, the middleware chain, URL resolution, the ORM from QuerySet to SQL compiler, lazy evaluation and N+1, select_related and prefetch_related, signals and their costs, the template engine, sessions and CSRF, and async support across the stack.
12
QuerySets underneath
code
qs = Transfer.objects.filter(status="completed").select_related("account__owner").order_by("-created_at")[:50]
print(qs.query) # SELECT ... FROM transfers INNER JOIN accounts ... INNER JOIN auth_user ... LIMIT 50
from django.db import connection, reset_queries
reset_queries(); render_page(); print(len(connection.queries)) # count queries (DEBUG=True only)
# aggregate in the database, not in Python
from django.db.models import Sum, Count
Transfer.objects.filter(created_at__date=today).values("account__currency").annotate(n=Count("id"), total=Sum("amount_kobo"))QUERYSETS AND THE N+1 PROBLEM
lazy QuerySets, and the two tools that fix most slow Django pages
swipe the figure sideways, or tap expand for full screen
1/5
lazy
Building a QuerySet runs no SQL; filters and orderings chain into one query that runs when you iterate, slice, call len() or list().
QuerySets are lazySQL runs on evaluation
13
Signals, sessions and async
| internal | what to know |
|---|---|
| signals (post_save, pre_delete) | synchronous, run inside the save; hidden control flow and extra queries; prefer explicit service functions |
| CSRF | a token per session checked on unsafe methods for cookie-authenticated requests; token-authenticated APIs (DRF with JWT) do not need it |
| sessions | database, cache or signed-cookie backends; Redis cache sessions scale best |
| async | async views and middleware work under ASGI; the ORM has async methods (aget, acount, async iteration) but transactions are still sync-oriented |
| app loading | INSTALLED_APPS order matters for templates, static files and signals; AppConfig.ready() for startup hooks |