Django comes packed with lots of wonderful shortcuts for rendering the correct response to a user. Shortcuts like get_object_or_404 which display 404 pages use the simple Http404 exception that comes with the http library. An example view:
from django.shortcuts import get_object_or_404
def my_view(request):
my_object = get_object_or_404(MyModel, pk=1)
In the background Django raises the Http404 exception which throws a message letting you know there wasn’t a matching query or slug. You may also raise the Http404 exception ala carte in your view like this:
from django.http import Http404
def my_view(request):
raise Http404
But what about the times when you need to let a user know that they do not have permissions to be there? For example, they may try to export data that doesn’t belong to them and we want to return a nice page with a message. In the background the http request should return a status 403 while the front end returns the message.
We could technically return the HttpResponseForbidden object in the view but that would require passing a template parameter and context to get the nice custom look we want. We can automate this. Instead of returning HttpResponseForbidden let’s create our own Http403 exception similar to the Http404 exception that automatically uses a 403.html template.
First, you want to create a middleware class that will handle the Http403 exception like so:
from django.template import RequestContext, loader
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseForbidden
class Http403(Exception):
pass
def render_to_403(*args, **kwargs):
"""
Returns a HttpResponseForbidden whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
if not isinstance(args,list):
args = []
args.append('403.html')
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
response = HttpResponseForbidden(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
return response
class Http403Middleware(object):
def process_exception(self,request,exception):
if isinstance(exception,Http403):
if settings.DEBUG:
raise PermissionDenied
return render_to_403(context_instance=RequestContext(request))
The middleware class Http403Middleware catches the Http403 exception in views and raises PermissionDenied (for debug=True) or returns render_to_403 (for debug=False). The middleware class must be placed in your Django settings under MIDDLEWARE_CLASSES.
Let’s assume that the code above is placed in an application called “base” and the file it resides in is called middleware.py. Then MIDDLEWARE_CLASSES would look like:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
# The HTTP 403 exception
'base.middleware.Http403Middleware',
)
Now you can create the 403.html template and place it in your templates directory provided in TEMPLATE_DIRS. That could look something like:
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title>The force is not with you today.</title>
</head>
<body>
<h1>The force is not with you today</h1>
<p>You cannot jedi mind trick your way into viewing this page, try again later.</p>
</body>
</html>
The last step is to raise the Http403 exception in your views when someone is denied access. Http403 exists in middleware.py according to the examples above but to better suite Django standards lets place it in a file called http.py. Here is an example of the view:
from django.shortcuts import render_to_response
from base.http import Http403
def index(request):
if not request.user.has_perm('app_label.permission'):
raise Http403
return render_to_response('app/view.html',{})
Another note: the render_to_403 function should be put in a file called shortcuts.py to stick to Django standards but you can put it where you want.
You can pretty much do this with any response code but 404 and 403 are the most common ones that require a front facing message. Happy Coding!

Cool! Thanks for sharing this with us.
I’m using this code in my Facebook’s application
Thanks for this.
Minor note: you need a couple additional imports to get the middleware code to actually work. The following works for me.
from django.template import RequestContext, loader
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseForbidden
Cheers.
Good catch. I’ll update it. Thanks!
Usefull thanks
If I don’t have permission in django admin, it will throw plain “Permission Denied” page. Can I use the above solution for customizing that also?
That’s a tricky one. You might want to try overriding the views using get_urls in the ModelAdmin:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls.
Once you override it you can do your own permission checks and then call the parent view. Start there and dig deeper. In my case we hardly ever used the Django Admin.