Get Django Custom Error Views Right the First Time!
Three things are infinitely complex: The Universe, Django’s crazy static file serving, and Django Custom Error Views. The infinity of the universe, no two ways about that, I’m pretty sure. However, the latter two, are infinitely more complex than the Universe!
I spent close to 2 hours today, simply trying to display a custom error message in my PackageToMe.com application.
As extensive as the Django documentation is, some areas are still as vague and infinite to understand in simple terms.
In this article, I wanna document, for myself and all reading, how to enable the Django Custom Error Views in no time.
Custom Error Views, why?
Why? Because the default looks horribly ugly, and unless you’re using no theme for your website, it doesn’t fit in the grand scheme of things on almost any website.
You don’t want the “Page Not Found” page looking skinny and disgraceful.
Custom Error Views
So, here we go.
According to the Documentation:
“The default error views in Django should suffice for most Web applications, but can easily be overridden if you need any custom behavior. Simply specify the handlers as seen below in your URLconf (setting them anywhere else will have no effect).”
Do you notice how vague the above is?
“Simply specify the handlers as seen below in your URLconf”?
Which of the URLconf? In a typical Django project, there can be as many as the number of apps available URLconf, so which one?
What kills me even is the beginning word, “Simply”. Geeesh!
Here are the steps to create your custom error views for your Django Application.
DEBUG Mode:
For any of the steps we do below to work for you to see true results, you have to set your DEBUG = True
. You don’t do that, Django won’t serve your custom error views, as in Debug mode True
, a traceback view is rather displayed by default.
Create the Views:
In any of your Django project apps, let’s call it main
(thus, DjangoProject
> main
), in the views.py
, add these:
# Error Pages def server_error(request): return render(request, 'errors/500.html') def not_found(request): return render(request, 'errors/404.html') def permission_denied(request): return render(request, 'errors/403.html') def bad_request(request): return render(request, 'errors/400.html')
Create the Templates:
In the DjangoProject/main/
folder, create an errors
folder in the templates
folder. So, you should end up with something like this:
DjangoProject/main/templates/errors
Create HTML files with the respective names above, as seen in the main/views.py
A typical example of one of the pages, such as the 404.html
might be this:
{% extends 'errors/error_base.html' %} {% block title %} Page Not Found Error 404 {% endblock %} {% block content %} <div class="card-header"> Page Not Found - Error 404 </div> <div class="card-block"> <p class="lead"> Your requested page, Not Found. </p> </div> {% endblock %}
where it extends from the error_base.html
file which might contain something like:
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="{% static 'vendor/bootstrap/dist/css/bootstrap.min.css'%}"> <title>{% block title %} Override Here {% endblock %} - Something wrong on PackageToMe</title> </head> <body> <div class="container" style="margin-top:20px;"> <div class="row"> <div class="col-sm-12 col-md-6 offset-md-3"> <div class="card"> {% block content %} Override here {% endblock %} </div> </div> </div> </div> </body> </html>
“Simply” change the content of the respective error messages templates to match them. Yes, I also used “Simply”!
Tell Django of Custom Views:
Now, just tell Django to go for the custom views you have created.
Go into DjangoProject/ProjectName/urls.conf
(same folder as settings.py
) and add the following:
# Other URL confs up here # Do not import anything for the handler404, # or whatnot from the django.conf.urls # Just list them below handler404 = 'main.views.not_found' handler500 = 'main.views.server_error' handler403 = 'main.views.permission_denied' handler400 = 'main.views.bad_request'
REMEMBER: If you add the error handlers to ANYWHERE except the urls.py
(in the same folder as the settings.py
, IT WON’T WORK!
- It WON’T WORK in
DjangoProject/main/urls.py
- It WON’T WORK in
DjangoProject/anotherapp/urls.py
- It WON’T WORK anywhere else apart from when specified in the
urls.py
file which is in SAME directory as thesettings.py
Run and Profit:
You should now be able to go into your browser, attempt opening a wrong URL, and you’ll be faced with your custom error view.
“Simply specify the handlers as seen below in your URLconf (setting them anywhere else will have no effect).”
Shaking My Head to vagueness!
NOTE: In Django 2.1+, you might need to use this:
def handler404(request, exception, template_name="404.html"): response = render_to_response("404.html") response.status_code = 404 return responseAs per recommended by Simon Eichenauer