多个Django应用使用相同的URL模式
我想让两个应用程序使用相同的URL模式。我希望避免像domain.com/pages/something-here或domain.com/blog/something-there这样的应用特定的路径。
我试过这样做:
# urls.py
urlpatterns = patterns('',
url(r'^$', 'my.homepage.view'),
url(r'^admin/', include(admin.site.urls)),
url(r'^', include('pages.urls')),
url(r'^', include('blog.urls')),
)
# pages/urls.py
urlpatterns = patterns('',
url(r'^(.+)/$', views.page),
)
# blog/urls.py
urlpatterns = patterns('',
url(r'^(.+)/$', views.post),
)
我的代码不管怎么写,先引入哪个(这里是pages.urls)就能正常工作,其他的URL(比如博客的)就会出现404错误。
提前谢谢你们!
编辑:我这样做了:在settings.py同一目录下创建了一个glue.py文件。它将处理我的主页和这个调度视图:
def dispatcher(request, slug):
try:
page = get_object_or_404(Page, slug=slug)
return render(request, 'pages/page.html', {'page': page})
except:
post = get_object_or_404(Post, slug=slug)
return render(request, 'blog/post.html', {'post': post})
我不知道这样是否合适。希望有更好的方法。
谢谢大家的评论。
3 个回答
你希望这个功能怎么实现呢?它们都在用同一个网址(这当然会造成问题)。用户怎么才能访问到“页面”而不是“博客”,或者反过来呢?
一般来说,你不能在网址模式中有重叠的网址(除非加上额外的数据)。
编辑:
所以你想让第一个应用检查一下它是否有可以匹配这个网址的视图,如果没有再让第二个应用接手?你可以做一些复杂的事情,比如写一个“视图匹配器”来实现你想要的,但其实有更简单的解决办法。
最简单的方法是修改其中一个应用的 slug
生成函数。让其中一个应用使用不同于下划线的分隔符,或者总是在 slug 后面加上应用的名字。这样你就能通过网址来区分页面和博客,比如页面的网址是“some-slug-page”,而博客的网址是“some-slug-blog”,这样你就可以为它们写出网址模式。如果你不想加上整个网址,也可以只加上第一个字母,或者你想要的任何东西。
只要想一个你觉得合适的方法来为每个应用生成网址,这样通过阅读网址就能知道这个页面属于哪个应用。
这个问题的原因在于,Django处理网址的顺序是有讲究的,也就是说,首先匹配到的那个网址就会被使用。在你的情况中,来自博客应用的网址永远不会被检查,因为Django在处理页面的包含行时已经找到了匹配的网址。
另外,Django的网址模块并不知道某个页面或博客文章是否存在,因为在你的应用中,这个是通过查询数据库来判断的。
网址模块只是执行与第一个匹配的正则表达式相关联的视图。
你应该改变一下你的逻辑,比如在博客网址前加上“blog/”(这样有什么问题呢?)
url(r'^blog/', include('blog.urls')),
url(r'^', include('pages.urls')),
注意,我把博客的网址放在了前面,因为大多数通用的正则表达式应该总是最后被Django的网址解析器尝试。
另外,你也可以写一个代理视图,尝试同时处理博客文章和页面,但我觉得这不是最好的方法。
我不知道这是不是更好的答案。不过,如果你满足以下情况的话……
你的Django应用是基于Django模板来渲染的。
你提到的那个网址,不需要直接在浏览器里输入地址来访问。
那么,也许你可以考虑使用网址命名空间和模板重定向。
https://docs.djangoproject.com/en/1.11/topics/http/urls/#url-namespaces