Django - catch exception
Asked Answered
I

4

11

Looking at this code:

try:
   ...  # do something
except:
   raise Exception('XYZ has gone wrong...')

Even with DEBUG=True, I don't want this raise Exception to give that yellow page, but it does.

I want to handle the exception by redirecting users to an error page or shows the error (give a CSS error message on the top of the page...)

How do I handle that? If I simply raise it, I will get yellow debug page (again, I don't want certain exceptions to stop the site from functioning by showing the debug page when DEBUG=True).

How do I handle these exceptions in views.py?

Immunochemistry answered 5/6, 2012 at 1:7 Comment(5)
@IgnacioVazquez-Abrams Thanks. But how does Django's form ValidationError achieve that? They don't raise exception. They just pass the exception as string to the views.Immunochemistry
@Immunochemistry they catch the exception within the form and handle it appropriately.Ster
@JoshSmeaton Thanks. The simplest solution to me is just pass the exception as string (same thing as don't raise one). But how can I utilise the keyword raise and follow the Django's style? Is there a slight modification to achieve that?Immunochemistry
@Immunochemistry you need to show us exactly what you're trying to do, and perhaps we can provide a better solution (one that you might not expect).Ster
@JoshSmeaton Thanks. I will edit in a bit...Immunochemistry
S
23

You have three options here.

  1. Provide a 404 handler or 500 handler
  2. Catch the exception elsewhere in your code and do appropriate redirection
  3. Provide custom middleware with the process_exception implemented

Middleware Example:

class MyExceptionMiddleware(object):
    def process_exception(self, request, exception):
        if not isinstance(exception, SomeExceptionType):
            return None
        return HttpResponse('some message')
Ster answered 5/6, 2012 at 1:16 Comment(2)
Thanks. THis is a great starting point. I will look at the documentation.Immunochemistry
@Immunochemistry You should click accept on this answer if you think it answers your question.Celiaceliac
H
4

You can raise a 404 error or simply redirect user onto your custom error page with error message

from django.http import Http404
#...
def your_view(request)
    #...
    try:
        #... do something
    except:
        raise Http404
        #or
        return redirect('your-custom-error-view-name', error='error messsage')
  1. Django 404 error
  2. Django redirect
Handcar answered 5/6, 2012 at 1:16 Comment(1)
Thanks. Another great starting point. I will spend the next few days trying out. Thanks!Immunochemistry
H
2

If you want to get proper traceback and message as well. Then I will suggest using a custom middleware and add it to the settings.py middleware section at the end.

The following code will process the exception only in production. You may remove the DEBUG condition if you wish.

from django.http import HttpResponse
from django.conf import settings
import traceback


class ErrorHandlerMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_exception(self, request, exception):
        if not settings.DEBUG:
            if exception:
                message = "{url}\n{error}\n{tb}".format(
                    url=request.build_absolute_uri(),
                    error=repr(exception),
                    tb=traceback.format_exc()
                )
                # Do whatever with the message now
            return HttpResponse("Error processing the request.", status=500)
Hardworking answered 24/1, 2020 at 12:31 Comment(0)
B
1

Another suggestion could be to use Django messaging framework to display flash messages, instead of an error page.

from django.contrib import messages
#...
def another_view(request):
    #...
    context = {'foo': 'bar'}
    try:
        #... some stuff here
    except SomeException as e:
        messages.add_message(request, messages.ERROR, e)

    return render(request, 'appname/another_view.html', context)

And then in the view as in Django documentation:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}
Blastoff answered 25/10, 2016 at 8:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.