如何高效管理日益复杂的Django URL视图?(urls.py)

2 投票
2 回答
1437 浏览
提问于 2025-04-15 18:48

我有一个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 个回答

0

让我们关注这个:

    # 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的回答,因为你可能在这里遇到了一些更深层次的问题。

3

为什么不使用GET参数,或者django-filter,如果你只是想以不同的方式过滤或分组结果呢?

我觉得使用GET的原因是,它更容易实现,而且看起来更整洁:在URL的方案中,/search/foo/user/bar/和/user/bar/search/foo/这两个地址其实是指向完全相同的内容。而使用GET参数的方案,所有内容都在同一个页面上。

撰写回答