Subclass handle_uncaught_exception

276 views
Skip to first unread message

Rory Campbell-Lange

unread,
May 14, 2012, 7:36:08 AM5/14/12
to django-d...@googlegroups.com
I have a custom database interface with (amongst other things) a lazy
rowgetter. Our database provides custom exception messages when, for instance,
a rate limit is exceeded.

Because of the "laziness" of the rowgetter, the except clause in my view
(shown below) is not triggered, and control falls to
core/handlers/base.py : handle_uncaught_exception.

try:
rota = self.model.xmlapi_get_location (**kwargs)
except DBException, e:
code, message = [epart.strip() for epart in e.msg.split(':')]
return HttpResponse(message, status=code,
content_type="text/plain")

I've tried the following:

* The use of middleware using "process_exception" : DBException not raised
* handler500 in urls : DBException not available

Consequently I believe I need to either make my lazy rowgetter less lazy so
that it errors earlier, or subclass handle_uncaught_exception. If the latter is
feasible I'd be grateful for some advice on how to do so within my app.

Rory

p.s.
An earlier version of this question was asked on Stack Overflow at
http://stackoverflow.com/questions/10574581/reroute-djangos-handle-uncaught-exception

--
Rory Campbell-Lange
ro...@campbell-lange.net

Campbell-Lange Workshop
www.campbell-lange.net
0207 6311 555
3 Tottenham Street London W1T 2AF
Registered in England No. 04551928

Rory Campbell-Lange

unread,
May 15, 2012, 1:31:16 PM5/15/12
to django-d...@googlegroups.com
On further investigation it appears that the process_exception
middleware isn't being called in my case. In other words,

/usr/lib/python2.7/dist-packages/django/utils/decorators.py:
92 except Exception, e:
93 import ipdb; ipdb.set_trace()
94 if hasattr(middleware, 'process_exception'):
95 result = middleware.process_exception(request, e)
96 if result is not None:
97 return result

I'm not familiar enough with Django to work out the relationship between
base.py and decorators.py. However the middleware class above does not have the
class I have loaded in base.py's self._exception_middleware. Should it have?

Rory

Rory Campbell-Lange

unread,
May 16, 2012, 7:32:45 AM5/16/12
to django-d...@googlegroups.com
I'm obviously whistling in the breeze here, but I'd be very grateful for
some help. I've provided some more info below.

I have a view raising a specific exception I would like to catch and
provide an HttpResponse based on this exception.

I cannot trigger the exception middleware either as standard middleware
or using decorator_from_middleware.

My middleware is as follows -- its simply a sketch at present:

class ExceptCatcher(object):
def process_exception(self, request, exception):
HttpResponse("Error encountered")

I have verified that the middleware is being loaded.

My attempt to load the middleware as a decorator (I'm using class-based views)
is as follows:

@decorator_from_middleware(ExceptCatcher)
def dispatch(self, *args, **kwargs):
return super(Locations, self).dispatch(*args, **kwargs)

In neither case is ExceptCatcher being seen by decorators.py where it
does an hasattr check on the middleware.

Tom Evans

unread,
May 16, 2012, 11:14:02 AM5/16/12
to django-d...@googlegroups.com
On Wed, May 16, 2012 at 12:32 PM, Rory Campbell-Lange
<ro...@campbell-lange.net> wrote:
> I'm obviously whistling in the breeze here, but I'd be very grateful for
> some help. I've provided some more info below.
>
> I have a view raising a specific exception I would like to catch and
> provide an HttpResponse based on this exception.

If it is one view raising one specific exception, why aren't you
catching it in that view? Exception middleware is used to provide a
more generic error page, or for advanced error handling, or to handle
errors from a number of views. If it is just for one view, one
exception, it is more coherent to handle the error in the view.

>
> I cannot trigger the exception middleware either as standard middleware
> or using decorator_from_middleware.
>
> My middleware is as follows -- its simply a sketch at present:
>
>    class ExceptCatcher(object):
>        def process_exception(self, request, exception):
>            HttpResponse("Error encountered")

Is this code verbatim? If so, you aren't returning the newly generated
HttpResponse, just creating it.

These sorts of questions should be on django-users really.

Cheers

Tom

rorycl

unread,
May 17, 2012, 4:51:31 AM5/17/12
to Django developers, Rory Campbell-Lange (CLW)
Hi Tom

Thanks for your email.

On May 16, 4:14 pm, Tom Evans <tevans...@googlemail.com> wrote:
> On Wed, May 16, 2012 at 12:32 PM, Rory Campbell-Lange
>
> <r...@campbell-lange.net> wrote:

> > I have a view raising a specific exception I would like to catch and
> > provide an HttpResponse based on this exception.
>
> If it is one view raising one specific exception, why aren't you
> catching it in that view? Exception middleware is used to provide a
> more generic error page, or for advanced error handling, or to handle
> errors from a number of views. If it is just for one view, one
> exception, it is more coherent to handle the error in the view.

As noted before in this thread I have a lazy rowgetter that only
triggers an exception
in the template. In other words, the except clause in my view isn't
triggered.

try:
rota = self.model.xmlapi_get_location (**kwargs)
except DBException, e:
code, message = [epart.strip() for epart in e.msg.split(':')]
return HttpResponse(message, status=code,
content_type="text/plain")

> > My middleware is as follows -- its simply a sketch at present:
>
> >    class ExceptCatcher(object):
> >        def process_exception(self, request, exception):
> >            HttpResponse("Error encountered")
>
> Is this code verbatim? If so, you aren't returning the newly generated
> HttpResponse, just creating it.

I'm simply trying to trigger the exception handler in ipdb and that is
not happening
using either either the standard middleware or
decorator_from_middleware
methodologies. I guess this might be because control has passed from
the view?
decorators.py:handle_uncaught_exception _is_ called, but I am unable
to interject my
ExceptCatcher with it.

> These sorts of questions should be on django-users really.

Sorry if this is the wrong place to post. However there are a number
of people on the
web reporting that they are unable to trigger process_exception. Hence
my query here.


Tom Evans

unread,
May 17, 2012, 11:05:32 AM5/17/12
to django-d...@googlegroups.com
Ah, you are returning a TemplateResponse? This changes things.

TemplateResponses are rendered outside of the view. Exception
middleware processes exceptions raised by the view, which this is not
- the view successfully completes and returns a valid HttpResponse
object.

I expect this may be a bug, or at least an unintended consequence.

This is all handled in django.core.handlers.base.BaseHandler. The view
is called here:

https://github.com/django/django/blob/master/django/core/handlers/base.py#L109

and if that raises an exception, Django will try to use the middleware
classes that have handle_exception() methods to generate a response.

If the returned response from the view is a template response, it is
rendered here:

https://github.com/django/django/blob/master/django/core/handlers/base.py#L133

if that raises an exception that isnt http.Http404,
exceptions.PermissionDenied or SystemExit, then it will use the
handle_uncaught_exception to handle the exception and return a
response.

I think this would need a new feature to fix. If a TemplateResponse
fails to render and throws an exception, you would want any middleware
that handles this to be passed both the exception and the
TemplateResponse that caused the exception, not just the exception
object.

I think you should raise a feature request ticket for this.

Cheers

Tom
Reply all
Reply to author
Forward
0 new messages