18

I have a project that I am working on in django. There are a lot of instances where I:

raise Http404("this is an error") 

and it creates a nice 404 page for me with the error message "this is an error" written on it.

I now want to create a custom error page and have it still display the message, but I can't figure out how.

I'm sure it's just a template variable that I need to add to my custom 404 template, but I can't find any documentation for it.

2
  • have you find the way of getting "this is an error" message into the custom 404 handler? @Alasdair, nbv4 i will really apretiate your help. Commented Oct 3, 2012 at 14:24
  • @marianobianchi I mistakenly said that it would be possible to use a custom 404 handler to acheive this, but it's not actually possible. There was a pull request for a required change, but it was turned down. After thinking about it, I agree with the decision. I think it's better to use the messages framework as Euribates suggests, or render a custom template and return status 404. If you include the exception messages in the default 404 template, there's a risk that you show unsuitable error messages to your end-users. Commented Aug 15, 2013 at 0:49

4 Answers 4

14

As of Django 1.9, the exception is passed to the page_not_found view which runs when you raise Http404. A representation of the error is passed to the template, you can include it in your template with:

{{ exception }} 

In earlier versions, the exception was not passed to the page_not_found view, so there wasn't an easy way to include the message from the exception in the template.

One possibility was to use the messages framework as @Euribates suggests in their answer. Another was to render a template and return a 404 status code in your view, instead of raising Http404.

Sign up to request clarification or add additional context in comments.

5 Comments

{{ exception }} only renders any custom message set in the view if DEBUG is set to True. If DEBUG = False, then {{ exception }} used in 404.html simply renders "Http404".
@DanSwain not sure I understand your comment. If DEBUG is True then Django displays the yellow page not found page. If DEBUG is False then the default view tries to show the message from the exception. If you see Http404 then the exception was probably raised without a message, e.g. raise Http404.
@Alasdair, here is the code I'm running: try: topic = Topic.objects.get(slug=slug) except Topic.DoesNotExist: raise Http404("Topic does not exist") When I set DEBUG to True, then "Topic does not exist" is shown in the yellow error page, but if I set DEBUG to False, then {{ exception }} in the standard 404.html template renders "Http404", not "Topic does not exist".
I just double checked {{ exception }} with the default page_not_found 404 handler, and it definitely displays the exception message in Django 2.0. If you still can't get it to work, please ask a new question with enough details to reproduce the problem.
If your message is replaced by the default one (here Http404), it might be because you're using gettext_lazy() instead of gettext()
9

There is another way. The code at page_not_found uses RequestContext; that means that you have access to all the variables defined by all the context processors defined in the TEMPLATE_CONTEXT_PROCESSORS entry in settings.py. The default value includes, among others, the django messages framework.

So, you con define the message you want to show using messages.error, for example, and show the message in the template using the messages variable.

In other words, you can write your view like this:

from django.contrib import messages from django.http import Http404 from django.template import RequestContext def my_view(request): # your code goes here if something_horribly_wrong_happened(): messages.error(request, 'Somethig horribly wrong happened!') raise Http404("It doesn't mind whatever you put here") else: return render_to_response( 'template.html', RequestContext(request, locals()), ) 

In your 404.html template, you should write something like:

{% if messages %} <ul class="messages"> {% for message in messages %} <li>{{ message }}</li> {% endfor %} </ul> {% endif %} 

It's a bit more complex, but it has the advantage you can send several messages, and even use diferent kind of messages (Warning, Debug, Info, Error, etc...) You can read more about the django message framework here: The messages framework | Django Documentation.

Comments

1

I have simpler solution

Just write middleware, that would take your error text into some request variable. See example

from django.http.response import Http404 class Error404Middleware(object): def process_exception(self, request, exception): if isinstance(exception, Http404): request.error_404_message = exception.message 

In 404.html

{{ request.error_404_message }} 

Comments

0

{{ exception }}

As of 1.9.6, the message passed to:

raise Http404('msg') 

is available from templates/404.html as:

{{ exception }} 

Source: https://github.com/django/django/blob/1.9.6/django/views/defaults.py#L20

5 Comments

@kd12345 thanks for the ping, but I'm afraid I haven't touched Django in a long while :-(
do you mind me asking what ORM are you using with python?
@kd12345 the only Python webdev I did was a bit of Django back in 2014, so I was just using their built-in ORM. I think it was decent. Now I'm picking webdev up again, but I'm seeing if there's any decent Node.js web framework to do server side rendering more easily. Having a though time though.
I am just starting to learn Django hence why my question may seen amateur. I am actually shifting from Node.js. Sequelize is a very powerful ORM if your using SQL. I really found it simple and very smooth to use.
@kd12345 cool, I did play with Sequelize and looking fine so far too!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.