Creating a custom 404 Page Not Found error page is so easy in Django (all you do is put your own template named “404.html” at the root of your templates directory) that I naturally assumed doing the same for a 403 Forbidden error page would be just as easy. Unfortunately it is not.
After searching around for quite a while last night, I found bits and pieces that I have modified slightly and republished below in a unambiguous step-by-step tutorial (see the “Source and Other Resources” section at the end of the post for a few of the source posts).
The method posted below leverages some custom Django middleware code. Please, if you have a better, more elegant solution I’d love to hear about it in the comments.
Create the Middleware
- Create a directory at the root of your project called “middleware”
- Add a file named “__init__.py” to this directory
- Create a file named “http.py” in this directory with the following contents:
from django.conf import settings from django.http import HttpResponseForbidden from django.template import RequestContext,Template,loader,TemplateDoesNotExist from django.utils.importlib import import_module """ # Middleware to allow the display of a 403.html template when a # 403 error is raised. """ class Http403(Exception): pass class Http403Middleware(object): def process_exception(self, request, exception): from http import Http403 if not isinstance(exception, Http403): # Return None so django doesn't re-raise the exception return None try: # Handle import error but allow any type error from view callback = getattr(import_module(settings.ROOT_URLCONF),'handler403') return callback(request,exception) except (ImportError,AttributeError): # Try to get a 403 template try: # First look for a user-defined template named "403.html" t = loader.get_template('403.html') except TemplateDoesNotExist: # If a template doesn't exist in the projct, use the following hardcoded template t = Template("""{% load i18n %} <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>{% trans "403 ERROR: Access denied" %}</title> </head> <body> <h1>{% trans "Access Denied (403)" %}</h1> {% trans "We're sorry, but you are not authorized to view this page." %} </body> </html>""") # Now use context and render template c = RequestContext(request, { 'message': exception.message }) return HttpResponseForbidden(t.render(c))
- You should now have this:
- /myproject/middleware/
- __init__.py
- http.py
- /myproject/middleware/
Modify Your Project’s “settings.py”
- Add ” ‘myproject.middleware.http.Http403Middleware’, ” to your MIDDLEWARE_CLASSES
Create a Custom “403.html” page
- Put it at the root of your template directory
- Sample content: (note: assumes you’ve already defined a “base.html” template)
{% extends "base.html" %} {% block title %} | Access Denied{% endblock %} {% block content %} <h1>Access Denied</h1> <span>We're sorry, but you are not authorized to view this page (Error: 403)</span> {% endblock content %}
Raise a 403 Error
- In the file where you want to raise the 403 add this at the top: (I used it in my project’s “view.py” file)
from myproject.middleware.http import Http403
- Raise the 403
if request.user.id != object.user.id: raise Http403
That’s it, you now have a Django template to handle 403 Forbidden errors. I’m sure there’s a way for your front-end, production web server to do the same, but I haven’t explored that yet.
Source and Other Resources
- A middleware solution is here (HT Felipe ‘chronos’ Prenholato)
- A middleware solution is here (HT Glen Zangirolami)
- A potential decorator solution is here (HT Magus)
9 Responses to “Show a Custom 403 Forbidden Error Page in Django”