[Django]-Tidy up complex URL dispatcher

5👍

The url maps are usually expressed explicitly, but they don’t have to be. How about building your URL map from your lists?

foo_urls = ['a', 'b', 'c'] #...
bar_urls = ['x', 'y', 'z'] #...

# A first pattern to get urlpatterns started.
urlpatterns = pattern('project.views', 
    ('blah', 'blah')
    )

# Append all the foo urls.
for foo_url in foo_urls:
    urlpatterns += patterns('project.views',
        ('^' + foo_url + '/$', 'foo')
        )

# Append all the bar urls.
for bar_url in bar_urls:
    urlpatterns += patterns('project.views',
        ('^' + bar_url + '/$', 'bar')
        )

4👍

Django’s url patterns are regular expressions, so this is indeed possible:

urlpatterns = patterns('project.views',
    (r'^[abc]/$', 'foo'),
    (r'^[xyz]/$', 'bar'),
)

If you’re using a, b, c as example placeholders for a non-single-character, you can use the full strings instead, but be careful to make sure they follow regex matching rules:

urlpatterns = patterns('project.views',
    (r'^(foo|slithy|toves)/$', 'foo'),
    (r'^(bar|twas|brillig)/$', 'bar'),
)

3👍

You could replace the urlpatterns with one that catches all the urls, then move the logic to choose between foo and bar urls to the view.

urlpatterns = patterns('project.views',
    (r'^(?P<letter>[a-z])/$', 'foobar'),
)

Then write a function foobar in views.py

def foobar(request, letter):

    foo_urls = ['a', 'b', 'c'] #...
    bar_urls = ['x', 'y', 'z'] #...
    if slug in foo_urls:
        return foo(request)
    if slug in bar_urls:
        return bar(request)
    else:
         #oh dear, you've caught a
         #url that isn't foo or bar
         #return 404?

As an alternative, you might want to explore the django redirects app, redesign the url structure, then set up redirects for the old urls.

1👍

If you’ve got Apache in front of your app:

<LocationMatch "^[a-w]/$">
   ...
</LocationMatch>

<LocationMatch "^[x-z]/$">
   ...
</LocationMatch>

The … can be any config directives you need, including SetEnv if you’d like an environment variable to tell you whether to go to foo vs bar, or maybe ProxyPass to send the request to a couple of different backend server urls.

You can also use url rewriting or a number of other Apache config settings that accept regex arguments.

Leave a comment