Tuesday, April 26, 2011

Adding information to Django's default error page

Django's default error page is a handy way find out what went wrong when your view code runs into an exception that is not explicitly handled. But sometimes you don't get the info you really want to see. For instance, today I kept running into sql errors, something I don't see too much of using Django because they are normally abstracted away by the model framework.

In my case I needed to resort to using raw sql. The query was complex and the variables many, and thus I encountered a number of different database (cx_oracle) errors while working on the view and I didn't have a quick and dirty way to see the sql that was generated.

Getting the most recently generated sql is possible by importing django.db.connections. You can then tack it into your exception and see it on the default error page using the following technique.



try:

"""
This is where you build your view. Do whatever you need to do. In my case
I was inserting a row into the database here.
"""
except Exception as inst:

"""
inst.args is a tuple of arguments that were passed when the exception
was raised. Django will turn this variable into the main error message
you see atop the default error page. It's a tuple, so you can't append
to it, but you can replace it with another tuple and add any information
that would serve you well.
"""

inst.args = ("%s sql:%s" % (inst.args[0], " ".join(connections[db].queries.pop()['sql'].split())),)

"""
Sure that's ugly, but it served my debugging purpose. Use pop to get the most
recent query from the queries list. I wanted to get rid of the while space and
newline characters, which is the reason for the split and join. Now you just
raise the exception.
"""
raise



If you are going to do this kind of thing frequently you should probably explore the process-exception middleware API.

http://docs.djangoproject.com/en/dev/topics/http/middleware/?from=olddocs#process-exception

Monday, April 25, 2011

Best Django debugging technique ever

Start up your test app using the Development Server. Then inject the following into your code where you want to examine everything, perhaps in an exception handler.


import pdb
pdb.set_trace


Now when you hit the exception, pdb will take over the console window you started the test app. Type help if you are unfamiliar with pdb. All of your variables are available for review!

Sweet! I can't believe I didn't know about this technique before.