如何高效管理日益复杂的Django URL视图?(urls.py)
我有一个Django应用程序,我不断添加新功能,以便更细致地查看数据。为了让你快速了解问题,这里有一部分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'),
可以看到,默认视图、日期视图、分页视图,还有针对用户的类似设置:
# 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'),
然后,团队的部分也是类似的……
# 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'),
现在,我想添加一个“搜索”视图,其实我觉得把这个功能加到上面很多URL的末尾会很好,这样我就可以访问像这样的链接:
/search/foo
/user/fred/date/2010-01/search/baz
然后我可以把搜索参数传给视图,这样就能适当地限制结果。
但是,如果我想把这个功能应用到用户、团队和按日期的视图上,我就得在urls.py
里添加大约12行新代码。而且每次我想添加另一个可能的视图选项(比如,分页搜索结果?)……我总觉得应该有更好的方法。
根据我的研究,似乎可以考虑以下方案:
1) 在urls.py
中进行更广泛的匹配,让视图函数解析查询字符串。
2) 也许在urls.py
中使用更复杂的正则表达式逻辑,可以说“如果这个模式匹配,就在传递给视图函数时包含这个参数”,这样可以多次使用。但这可能会让维护变得很麻烦。
有没有人想出更聪明的解决方案,优雅地管理复杂的URL?我在想,到了某个时候,直接把参数匹配的逻辑交给视图本身来处理,从查询字符串中解析参数,可能是最简单的。因此,在视图的顶部,我可能会有一些看起来像这样的代码:
# 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')
那么,这样做是否是减少我在urls.py
中引入的重复复杂性的聪明方法呢?
2 个回答
让我们关注这个:
# 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'),
我假设这里有一些:
def index(year=2010, month=2, day=2, page=0):
# whatever
那么,为什么不把你的正则表达式合并成一个呢,比如:
r'^date/(?P<year>\d{4})(-(?P<month>\d{2})(-(?P<day>\d{2}))?)?$
我没有试过,但我很确定像这样的东西应该能工作。
编辑:
虽然重写正则表达式可能有效,但看看Ofri Raviv的回答,因为你可能在这里遇到了一些更深层次的问题。
为什么不使用GET参数,或者django-filter,如果你只是想以不同的方式过滤或分组结果呢?
我觉得使用GET的原因是,它更容易实现,而且看起来更整洁:在URL的方案中,/search/foo/user/bar/和/user/bar/search/foo/这两个地址其实是指向完全相同的内容。而使用GET参数的方案,所有内容都在同一个页面上。