So, I have this Django application and I keep adding new features to provide ever more granular views of the data. To give a quick idea of the problem, here's a subset of urls.py
:
# Simple enough . . .
(r'^$', 'index'),
(r'^date/(?P<year>\d{4})$', 'index'),
(r'^date/(?P<year>\d{4})-(?P<month>\d{2})$', 'index'),
(r'^date/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$', 'index'),
(r'^page/(?P<page>\d+)$', 'index'),
So, yeah, the default view, date views, a paginated view, then a similar setup for user-specific URLs:
# user
(r'^user/(?P<username>\w+)$', 'index_username'),
(r'^user/(?P<username>\w+)/date/(?P<year>\d{4})$', 'index_username'),
(r'^user/(?P<username>\w+)/date/(?P<year>\d{4})-(?P<month>\d{2})$', 'index_username'),
(r'^user/(?P<username>\w+)/date/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$', 'index_username'),
(r'^user/(?P<username>\w+)/page/(?P<page>\d+)$', 'index_username'),
Then, similar again for Teams . . .
# Team View
(r'^team/(?P<team>\w+)$', 'index'),
(r'^team/(?P<team>\w+)/date/(?P<year>\d{4})$', 'index'),
(r'^team/(?P<team>\w+)/date/(?P<year>\d{4})-(?P<month>\d{2})$', 'index'),
(r'^team/(?P<team>\w+)/date/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$', 'index'),
(r'^team/(?P<team>\w+)/page/(?P<page>\d+)$', 'index'),
Now, I want to add a "search" view, and really I think it'd be nice to just add that to the end of many of the above URLs, so I could hit something like:
/search/foo
/user/fred/date/2010-01/search/baz
And then I could just pass a search parameter to the view, which could constrains the results appropriately.
But say, if I want to apply that to the user, team, and by-date views, I've got what 12 new lines added to urls.py
. And each time I add another potential view option (say, paginated search results?) . . . it just feels like there ought to be a better way.
From my research, the answer would seem to be:
1) Broader matching within urls.py
and have the view function parse the query string.
2) Maybe some beefier regular expression logic in urls.py
that can say "if this pattern matches, include the parameter when passing to the view function" multiple times. But that's possibly nightmarish to maintain.
Has anyone conjured a wiser solution to managing complex URLs elegantly? I'm thinking that at a certain point it is cleanest simply to pass the parameter-matching logic to the view itself, to parse parameters out of the query string. So, near the top of the view I might have some code that looks like this:
# Date Queries
re_ymd = re.compile('date/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})')
re_ym = re.compile('date/(?P<year>\d{4})-(?P<month>\d{2})')
re_y = re.compile('date/(?P<year>\d{4})')
if( re_ymd.search(qs) ):
year = re_ymd.search(qs).group('year')
month = re_ymd.search(qs).group('month')
day = re_ymd.search(qs).group('day')
elif( re_ym.search(qs) ):
year = re_ym.search(qs).group('year')
month = re_ym.search(qs).group('month')
elif( re_y.search(qs) ):
year = re_y.search(qs).group('year')
# Pagination queries
re_p = re.compile('page/(?P<page>\d+)')
if( re_p.search(qs) ):
page = re_p.search(qs).group('page')
# Search queries
re_s = re.compile('search/(?P<search>\w+)')
if( re_s.search(qs) ):
search = re_s.search(qs).group('search')
So, is that the clever way of reducing the repetetive complexity I have been introducing to urls.py
?