Last quarter a fintech client came to us with a familiar complaint: their Django dashboard felt slow, users were complaining, and nobody could pinpoint why. Four weeks later the average page load was 68% faster. Here's the playbook.
Measure first, optimise second. We wired up django-debug-toolbar and silk, reproduced real traffic, and found the top offender: a template rendering 340 queries per page — the classic N+1.
Kill the N+1s. select_related for foreign keys, prefetch_related for reverse relations. The 340 queries became 14. This alone halved load time.
Cache what doesn't change often. Template fragment caching on the sidebar and stats widgets, backed by Redis, with a 5-minute TTL. Fresh enough for the business, fast enough for users.
Move slow work out of the request. Report generation moved to Celery with a progress bar. Users stopped watching spinners and started getting e-mails when exports were ready.
Compress and lazy-load everything. WebP images, lazy loading below the fold, and gzip at the proxy level shaved another 300ms on mobile.
The result: 4.1s → 1.3s, bounce rate down 19%, and a very happy operations team. Performance work is never glamorous, but it is the cheapest UX upgrade you can buy.