Andy McKay

Apr 19, 2009

Django urlpatterns - it's more than just urls


In this project we are processing text messages. So peice of text comes into a method and needs to be routed to a particular view/method/class/thing. There's lots of ways of doing it, a big if might be one. RapidSMS includes a damn cunning way of doing it by using decorators.

Here's an example:

    @keyword(r'n(?:ote)? \+(\d+) (.+)')
    @authenticated
    def note_case (self, message, ref_id, note):
         [...]

I thought that was really neat, you can see the decorator here. Nice stuff!

However since I'm a GOD (Grumpy Old Developer) after using it for about 10 minutes I see there's a basic problem I'm not happy with: I find it hard to track what message goes where. There could be 100's of lines of code between each decorator, its hard to see them all at once.

Hmm. So how about using Django's urlpatterns? I actually like the url regex in Django because it's easy to see in one editor window what is going where.

In my case I made a file: msgs.py that simply maps the regex's to the view:

from django.conf.urls.defaults import patterns

urlpatterns = patterns('',
    (r'^country (?P\S+)', "apps.testy.views.country",),
    (r'^list (?P\S+)', "apps.testy.views.list",),
)
</pre>

Then in my app I can use the URLResolver:

from django.core.urlresolvers import RegexURLResolver, Resolver404

resolver = RegexURLResolver(r'', "apps.testy.msgs")

In my class I'm able to use the resolver in a method, on any text:

       try:
            callback, callback_args, callback_kwargs = resolver.resolve(text)
        except Resolver404:
            raise ValueError, "There was no view found for: %s" % text
            
        response = callback(self, message, *callback_args, **callback_kwargs)

And now I can pass text through to different views based on those regex's. The only problem with it is that (understandably) it's using HTTP semantics. That Resolver404 inherits from a HTTPError, which isn't ideal for a non HTTP source. Also it's kind of annoying having to call it urlpatterns in msgs.py since they aren't really about URL's.

So then that's where I'd say something like: I've ripped urlpatterns out of Django, made it generic, placed it on pypi, then put a Django wrapper around it for URL'ishness and put it back into the Django project. Except I haven't. But if you were doing a project that included doing logic on a bit of text.... perhaps you could do that.