Strange Django Error

Author: Jeff Anderson

I was porting Smug to work with Django 1.0, and I got a very, very, strange error when I'd try to go to the admin site. The template renderer was throwing TemplateSyntaxError when trying to access /admin/. I was very confused:

Template error:
In template /users/admin/jefferya/sandbox/django/django/contrib/admin/templates/admin/base.html, error at line 25
   Caught an exception while rendering: Non-reversible reg-exp portion: '(?x'
   25 :         <div id="user-tools">{% trans 'Welcome,' %} <strong>{% firstof user.first_name user.username %}</strong>. {% block userlinks %} {% url django-admindocs-docroot as docsroot %} {% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}<a href="{{ root_path }}password_change/">{% trans 'Change password' %}</a> / <a href="{{ root_path }}logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
Traceback:
...
...
File "/users/admin/jefferya/sandbox/django/django/template/debug.py" in render_node
  81.             raise wrapped

Exception Type: TemplateSyntaxError at /admin/
Exception Value: Caught an exception while rendering: Non-reversible reg-exp portion: '(?x'

I've edited out a lot of the extra stuff, and included the most important parts.

The {% url %} tag in the admin template was the thing throwing the error.

Googling didn't really help-- the only thing that looked remotely like the error message was the code itself as seen on http://code.djangoproject.com/.

I was using Andrew's smug app. The urls.py for smug included a verbose regular expression. There are two ways to tell Python that a regex is verbose. One is to include the x flag. That is what the (?x) was there for.

Django's URL resolver never was able to reverse verbose regular expressions-- it'd just wouldn't work. In Django r8760, the URL resolver was re-written. The new one explicitly didn't work with verbose regular expressions. The only problem with the way it handles verbose regular expressions is that it dies on any {% url %} tag in any app, even the admin app, if there is even one verbose regular expression in the urlconf.

This made it very strange to diagnose. While I do contribute to smug, I've not done anything with the regular expressions in the urlconf, and I've never really used python verbose regular expressions.

I'm not sure that Django should support reverse url mapping to verbose regular expressions, but I'm sure that if I happen to choose to include one in a third party app, or in my own urlconf, that it shouldn't break all reverse url mapping.

I'm not 100% sure what the best way is to get rid of this strange behavior. I think that if it sees a verbose regular expression, it should ignore it and try to make a mapping against the regular expressions that it does understand. If it fails to write a URL, then it could throw an exception about verbose regular expressions.

I need to dive into the reverse url mapping code and see how it works. I may just feel up to adding support for verbose regular expressions. In the end, they really aren't that different from normal regular expressions.

The workaround that Andrew found for the Smug urls was to do this:

    url(r'^(?P<page>[-\w\./]*)'  # page must always be given, but may be empty
            r'(\((?P<branch>[/\w]+)\))?'  # branch may optionally be given
            r'$', views.show, {'session': False}, name='smug_show'),

You effectively get verbose regular expressions, without the verbose flag. (r'one/' r'two/' r'three/') is the same as (r'one/two/three/'). Andrew believes that if anything needs comments, that it is definitely regular expressions. I agree to some point, but I'm just as happy with putting comments above or below the regex-- I don't necessarily feel that I need to break up the regex itself, although I can appreciate being able to do so.

Posted: Sep 20, 2008 | Tags: Django Smug

Comments are closed.