views:

404

answers:

3

Can someone please explain how you can write a url pattern and view that allows optional parameters? I've done this successfully, but I always break the url template tag.

Here's what I have currently:

Pattern

(r'^so/(?P<required>\d+)/?(?P<optional>(.*))/?$', 'myapp.so')

View

def so(request, required, optional):

If I use the url template tag in this example providing both arguments, it works just fine; however, if I omit the optional argument, I get a reversing error.

How can I accomplish this?

Thanks, Pete

+2  A: 

I generally make two patterns with a named url:

url(r'^so/(?P<required>\d+)/$', 'myapp.so', name='something'),
url(r'^so/(?P<required>\d+)/(?P<optional>.*)/$', 'myapp.so', name='something_else'),
Todd Gardner
Yes, this is the usual way to do it. The URL-reverser has only limited smarts about regexes (it doesn't implement a full regex parser), and it can't handle optional parts. You are free to use the full power of regexes in your URL patterns, but then you give up URL reversing.
Carl Meyer
Thanks, this is what I was looking for. Was surprised to learn I needed two separate URLs.
slypete
A: 

Why not have two patterns:

(r'^so/(?P<required>\d+)/(?P<optional>.*)/$', view='myapp.so', name='optional'),
(r'^so/(?P<required>\d+)/$', view='myapp.so', kwargs={'optional':None}, name='required'),
hughdbrown
It doesn't matter which order you put these URL patterns in. They both are bounded with $ at the end, so there can be no ambiguity. There are, of course, similar situations where it would matter (if the shorter pattern were unbounded, for instance).
Carl Meyer
Hmmmm. Will edit.
hughdbrown
+2  A: 

Others have demonstrated the way to handle this with two separate named URL patterns. If the repetition of part of the URL pattern bothers you, it's possible to get rid of it by using include():

url(r'^so/(?P<required>\d+)/', include('myapp.required_urls'))

And then add a required_urls.py file with:

url(r'^$', 'myapp.so', name='something')
url(r'^(?P<optional>.+)/$', 'myapp.so', name='something_else')

Normally I wouldn't consider this worth it unless there's a common prefix for quite a number of URLs (certainly more than two).

Carl Meyer
Thanks Carl, this looks like it will come in handy too.
slypete