Chapter 5: Django 404 (page not found)

What Actually Happens When Django Returns 404?

  1. User requests a URL (e.g. /polls/this-question-does-not-exist/)
  2. Django checks all patterns in urls.py (project + included apps)
  3. No match → Django raises Http404 exception internally
  4. Django catches it and looks for a custom 404 handler
  5. If nothing custom → shows default “Not Found” debug page (DEBUG=True) or plain white “404 Not Found” (DEBUG=False)

Goal today: Replace both the ugly debug page and the boring server default with your own beautiful, branded 404 page.

Step 1: Create the 404 Template (Simplest & Most Common Way)

Django automatically looks for a file called 404.html in these locations (in order):

  1. Folders in TEMPLATES[‘DIRS’] (your project-level templates/ folder)
  2. Each app’s templates/ subfolder

Recommended place: project-level templates/404.html

Create it:

Bash

Now mysite/templates/404.html:

HTML
  • Extends your base.html → keeps header, nav, footer consistent
  • Friendly tone (Hyderabad style 😄)
  • Clear call-to-actions (home + polls list)

Step 2: Make Sure Django Finds It (settings.py)

In mysite/settings.py → make sure:

Python

If ‘DIRS’ is empty → Django won’t look in project-level templates/

Step 3: Test It (Two Ways)

Way A – DEBUG = True (development)

Just visit a wrong URL:

http://127.0.0.1:8000/polls/non-existing-slug/

→ You should see your custom 404.html instead of the yellow Django debug page

Way B – DEBUG = False (production simulation)

Temporarily set in settings.py:

Python

Visit same wrong URL → should show your 404 page (not the plain “Not Found” text)

Important: After testing → set DEBUG = True back!

Step 4: Bonus – Custom 404 View (When You Want Logic)

Most projects don’t need this — the template is enough.

But if you want (e.g. log 404s, show suggested polls, etc.):

In mysite/views.py (create file if missing):

Python

In mysite/urls.py (at the very bottom):

Python

Now Django calls your view instead of auto-template lookup.

When to use custom view:

  • Want to pass extra context (suggested articles, search form…)
  • Log 404s to analytics/sentry
  • Show different 404 for logged-in vs anonymous

Most people (including me in 2026): just use 404.html template — simpler.

Step 5: Also Prepare 500.html (Server Error)

Create templates/500.html — same style:

HTML

Django auto-uses 500.html when DEBUG=False and a server error occurs.

Quick Checklist – Did You Do It Right?

  • templates/404.html exists
  • TEMPLATES[‘DIRS’] includes BASE_DIR / ‘templates’
  • Extends base.html (keeps navigation & design)
  • Tested with wrong URL → custom page shows
  • Tested with DEBUG=False → still looks good

Common “Why Is It Not Working?” Moments

Symptom Likely Cause Fix
Still see yellow debug page DEBUG = True (normal in dev) Nothing — debug page only shows when DEBUG=True
Blank or default “Not Found” DEBUG = False + no 404.html Create templates/404.html
TemplateDoesNotExist: 404.html Wrong folder or missing in DIRS Check path & settings
404 page shows but no style / header Forgot {% extends “base.html” %} Add extends at the very top
Custom view not called handler404 not set in urls.py Add handler404 = ‘mysite.views.custom_404’

Your Quick Task Right Now

  1. Create templates/404.html as shown
  2. Visit a nonsense URL (e.g. /polls/iamnotreal/ or /random-page/)
  3. Confirm your nice branded 404 appears
  4. (Optional) Temporarily set DEBUG=False, test again, revert back

Tell me what’s next:

  • “It works! Now show me custom 500 page + error logging”
  • “How to make 404 suggest similar polls or search?”
  • “I want funny 404 messages that change randomly”
  • “Got wrong page / still debug screen – here’s what I see”
  • Or finally ready for: “Let’s finish voting – POST form + F() increment”

You’ve just made your app much more user-friendly — small detail, big difference. You’re doing really well — let’s keep going! 🚀🇮🇳

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *