Customizing 404 Not Found page in Django

This article shows how to customize 404 (not found) page on your Django website.

In production mode (DEBUG = False), Django displays the default 404 page if the resource does not exist. When you raise Http404 exception in a view, Django invokes a special view which is added to handle 404 errors. By default, the Django handler404 view is django.views.defaults.page_not_found(). This view either displays a “Not Found” message or renders the template 404.html if you added it to your root template directory. 

Default 404 page (Production only)

Let's assume the default 404 page does not fit our needs. So we need to add a new template to your root template directory and name it 404.html.

{% extends 'base.html' %}
{% load static %}

{% block title %} Posts {% endblock %}

{% block content %}
    <div class="mt-3">
        <div class="container">
            <h3>Not Found</h3>
        </div>
    </div>
{% endblock %}

In our case, the root template directory is defined in ‘DIRS’ key: 'DIRS': [os.path.join(BASE_DIR, 'templates')]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Next, to test it add a view and call it post_detail, which raises the Http404 exception if the post is not found with the given slug.

def post_detail(request, slug):
    try:
        post = models.Post.objects.get(slug=slug)
    except models.Post.DoesNotExist:
        raise Http404

    return render(
        request,
        'blog/post-detail.html',
        context={'post': post}
    )

If you are running the website in debug mode (DEBUG = True in settings.py) it does not render a 404.html template, instead, it renders URLconf with some debug information.

To see the custom 404 page in action change DEBUG to False and got to the non-existing page or /post/<non-existing-slug>. You should now see the custom 404 page:

Custom 404 page