Wednesday, November 11, 2009

When Django Fails? (A response)

I saw an article on reddit (or was in hacker news?) that asked the question: what happens when newbies make typos following the Rails tutorial, and how good of a job does Rails do at giving useful error messages? I decided it would be interesting to apply this same question to Django, and see what the results are. I didn't have the time to review the entire Django tutorial, so instead I'm going to make the same mistakes the author of that article did and see what the results are, I've only done the first few where the analogs in Django were clear.

Mistake #1: Point a URL at a non-existent view:

I pointed a URL at the view "django_fails.views.homme" when it should have been "home". Let's see what the error is:

ViewDoesNotExist at /
Tried homme in module django_fails.views. Error was: 'module' object has no attribute 'homme'

So the exception name is definitely a good start, combined with the error text I think it's pretty clear that the view doesn't exist.

Mistake #2: misspell url in the mapping file

Instead of doing url("^$" ...) I did urll:

NameError at /
name 'urll' is not defined

The error is a normal Python exception, which for a Python programmer is probably decently helpful, the cake is that if you look at the traceback it points to the exact line, in user code, that has the typo, which is exactly what you need.

Mistake #3: Linking to non-existent pages

I created a template and tried to use the {% url %} tag on a nonexistent view.

TemplateSyntaxError at /
Caught an exception while rendering: Reverse for 'homme' with arguments '()' and keyword arguments '{}' not found.

It points me at the exact line of the template that's giving me the error and it says that the reverse wasn't found, it seems pretty clear to me, but it's been a while since I was new, so perhaps a new users perspective on an error like this would be important.

It seems clear to me that Django does a pretty good job with providing useful exceptions, in particular the tracebacks on template specific exceptions can show you where in your templates the errors are. One issue I'll note that I've experience in my own work is that when you have an exception from within a templatetag it's hard to get the Python level traceback, which is important when you are debugging your own templatetags. However, there's a ticket that's been filed for that in Django's trac.


  1. Also when you have an error in reversing a URL, it's very tricky to tell where it went wrong.

  2. Eric: That's definitely true, sometimes you can get an error just because one of your other URLs doesn't point to a valid view. However for simple mistakes (the kind new users are likely to make) on small sites the exception gives you a good amount of info to work with.

  3. I agree with Eric. Reverse errors suck big time. So much so, I no longer believe it to be worth using them. Too many hours spent trying to debug blindly because of them and at the end of the day they provide very little marginal value.

  4. Of course, the error traces are not always the most descriptive ones, but i think Dango traces are quite good.

    At least compared with Grails (which I also has to use, I should say "suffer"), which rely on the confusing Java stack trace, which I think it's very close to the worst debugging info ever

  5. The biggest issue I have is that model syncing fails silently (it's as if the app doesn't exist) if an import in the app models file dies with an exception (for instance, not found).

  6. Eric, Alex, Patrick: Wouldn't it be possible to re-write the TemplateSyntaxError to find these? I wrote some code in that area that would figure out what line in your template you forgot to put {% endfor %} or {% with ... %} or whatever else was wrong. This was work done during the 2009 PyCon sprint but sadly the code got really messy and ugly as it relied on inspect and flipping through frames.
    Has anybody else attempted a hack like this but with some neat (non-django-dev-beginner) and code and decent test coverage?

  7. It fails big time providing meaningful exceptions at:
    - URL/reverse errors
    - View code causing URL/reverse errors at runtime
    - Anything that raises an exception at template rendering: template tags, form widgets, cache...

    Most of the exceptions are clean, but when you hit an error and template starts swallowing debug info from you, grab a soda because most likely the next 30 minutes of debugging are going to suck.

  8. "Reverse ... not found" and "raise wrapped" are probably the most annoying error messages in Django. Until you have solved a number of such issues, the intuition does not guide you and the logic stalls.

  9. I think Django does a pretty good job in general, but there are a few cases that drives me nuts. Two have already been mentioned:

    1. URL/reverse errors
    2. Errors coming from template tags
    3. If there's an error in a template that is included in another with the "include" tag, that include is simply not rendered. No error, no nothing.

    That last one kills me ALL the time (and if you're going to tell me not to use the "include" tag, you can save it, because I promise you I've used the Django template language more extensively than you, no matter who you are. :)

  10. Django fails to show non-latin exception messages from PostgreSQL running on FastCGI
    Reported by: Loststylus Assigned to: nobody
    Milestone: Component: Core framework
    Version: 1.1-beta-1 Keywords:
    Cc: Triage Stage: Unreviewed
    Has patch: 0 Needs documentation: 0
    Needs tests: 0 Patch needs improvement: 0
    Description ¶

    Run django via FastCGI (used nginx 0.6.x to deploy) with PosgreSQL. Try to execute some query, that will produce an error. If the error returned by PosgreSQL is not latin (Russian in my case), django tries to render an error page, but fails. nginx return a page with "Unhandled exception"

    If you turn on debug in flup, you will see the traceback, that shows that django tries to force_unicode the error message and fails with UnicodeDecodeError?, so the user cannot determine the problem.

    I'll attach a flup error page with stack trace.


Note: Only a member of this blog may post a comment.