Go to a non existent page on a Django site and you will (hopefully) be met with a friendly error page telling you not to panic, everything is OK and all you’ve done is mistyped the URL or something.
If it’s your thing, you may be interested enough to look see what the actual HTTP code for the page is in the header; chances are that it will be a 200 rather than a 404 as the default handler just passes the dealings onto the HttpResponse class.
Generally speaking this is fine, but there are situations where an accurate code would be very handy, as I found out the other day when I was trying to detect whether a file had been uploaded to a remote server. Scraping the resultant HTML for “Page not found” is not my idea of a robust solution.
So, instead, pass the error page’s HTML into the respective class by putting something like this in urls.py:
handler404 = 'urls.return_404'
handler500 = 'urls.return_500'
def return_404(request):
return HttpResponseNotFound(
render_to_string("errors/404.html"))
def return_500(request):
return HttpResponseServerError(
render_to_string("errors/500.html"))
Fullest of props to PiotrLegnica at Stack Overflow for this most elegant of solutions.
Edit: After further examination (see the comments) the default handlers do act as expected, but you’re still restricted to where you put your error templates, i.e. the root of the templates directory.
To my mind, it’s neater if you can specify a dedicated location.
Since the default error views do the right thing, and the request/response documentation lists both how to have a normal HttpResponse use your preferred status code and how to use the assorted subclasses for common status codes, I’m a bit curious as to what sort of trouble you had finding this information.
Not sure I get you, are you curious about the solution or that I missed it in the documentation?
What struck me about the default behaviour was how the codes aren’t honoured, returning a 200 for a 404 even after explicitly setting them in the view, so necessitating this approach.
I think that James is getting at the fact that the default 404/500 methods *already* use the correct error codes. See for yourself:
http://code.djangoproject.com/browser/django/tags/releases/1.0/django/views/defaults.py
http://code.djangoproject.com/browser/django/trunk/django/views/defaults.py
Ah, got you – the penny drops.
From looking over the code on the remote server, the custom error handlers were just using render_to_response, hence the 200 and blind assumption on my part.
We did still need the ability to specify the location of the templates, so not an entirely fruitless exercise
My mistake, I’ll edit the OP accordingly.