views:

368

answers:

4

I have two different kinds of objects that I'd like to live under the same URL. One group of objects needs to be passed to the view function 'foo' and another group needs to be passed to 'bar'.

I'm currently doing this with a big long list of hardcoded URLs, like so...

urlpatterns = patterns('project.views',
    (r'^a/$', 'foo'),
    (r'^b/$', 'foo'),
    (r'^c/$', 'foo'),
    #...and so on until...
    (r'^x/$', 'bar'),
    (r'^y/$', 'bar'),
    (r'^z/$', 'bar'),
)

Is it possible to define a list of each type of URLs like...

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

...and then check the incoming URL against those lists? (If it's in 'foo_urls', send to 'project.views.foo'; if it's in 'bar_urls', send to 'project.views.bar')?

I'm limited to keeping this structure to maintain compatibility with the URLs from the previous site, but any advice on ways to simplify my urls.py would be much appreciated.

+3  A: 

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'),
)
Jarret Hardie
+4  A: 

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')
        )
Ned Batchelder
+3  A: 

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.

Alasdair
+1  A: 

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.

DougWebb