包含其他URLconf

如果你试图让你的代码用在多个基于Django的站点上,你应该考虑将你的URLconf以包含的方式来处理。

在任何时候,你的URLconf都可以包含其他URLconf模块。 对于根目录是基于一系列URL的站点来说,这是必要的。 例如下面的,URLconf包含了其他URLConf:

  1. from django.conf.urls.defaults import *
  2. urlpatterns = patterns('',
  3. (r'^weblog/', include('mysite.blog.urls')),
  4. (r'^photos/', include('mysite.photos.urls')),
  5. (r'^about/$', 'mysite.views.about'),
  6. )

在前面第6章介绍Django的admin模块时我们曾经见过include. admin模块有他自己的URLconf,你仅仅只需要在你自己的代码中加入include就可以了.

这里有个很重要的地方: 例子中的指向 include() 的正则表达式并 包含一个 $ (字符串结尾匹配符),但是包含了一个斜杆。 每当Django遇到 include() 时,它将截断匹配的URL,并把剩余的字符串发往包含的URLconf作进一步处理。

继续看这个例子,这里就是被包含的URLconf mysite.blog.urls

  1. from django.conf.urls.defaults import *
  2. urlpatterns = patterns('',
  3. (r'^(\d\d\d\d)/$', 'mysite.blog.views.year_detail'),
  4. (r'^(\d\d\d\d)/(\d\d)/$', 'mysite.blog.views.month_detail'),
  5. )

通过这两个URLconf,下面是一些处理请求的例子:

  • /weblog/2007/ :在第一个URLconf中,模式 r'^weblog/' 被匹配。 因为它是一个 include() ,Django将截掉所有匹配的文本,在这里是 'weblog/' 。URL剩余的部分是 2007/ , 将在 mysite.blog.urls 这个URLconf的第一行中被匹配到。 URL仍存在的部分为 2007/ ,与第一行的 mysite.blog.urlsURL设置相匹配。

  • /weblog//2007/(包含两个斜杠) 在第一个URLconf中,r’^weblog/’匹配 因为它有一个include(),django去掉了匹配的部,在这个例子中匹配的部分是’weblog/’ 剩下的部分是/2007/ (最前面有一个斜杠),不匹配mysite.blog.urls中的任何一行.

  • /about/ : 这个匹配第一个URLconf中的 mysite.views.about 视图。

捕获的参数如何和include()协同工作

一个被包含的URLconf接收任何来自parent URLconfs的被捕获的参数,比如:

  1. # root urls.py
  2. from django.conf.urls.defaults import *
  3. urlpatterns = patterns('',
  4. (r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
  5. )
  6. # foo/urls/blog.py
  7. from django.conf.urls.defaults import *
  8. urlpatterns = patterns('',
  9. (r'^$', 'foo.views.blog_index'),
  10. (r'^archive/$', 'foo.views.blog_archive'),
  11. )

在这个例子中,被捕获的 username 变量将传递给被包含的 URLconf,进而传递给那个URLconf中的 每一个 视图函数。

注意,这个被捕获的参数 总是 传递到被包含的URLconf中的 每一 行,不管那些行对应的视图是否需要这些参数。 因此,这个技术只有在你确实需要那个被传递的参数的时候才显得有用。

额外的URLconf如何和include()协同工作

相似的,你可以传递额外的URLconf选项到 include() , 就像你可以通过字典传递额外的URLconf选项到普通的视图。 当你这样做的时候,被包含URLconf的 每一 行都会收到那些额外的参数。

比如,下面的两个URLconf在功能上是相等的。

第一个:

  1. # urls.py
  2. from django.conf.urls.defaults import *
  3. urlpatterns = patterns('',
  4. (r'^blog/', include('inner'), {'blogid': 3}),
  5. )
  6. # inner.py
  7. from django.conf.urls.defaults import *
  8. urlpatterns = patterns('',
  9. (r'^archive/$', 'mysite.views.archive'),
  10. (r'^about/$', 'mysite.views.about'),
  11. (r'^rss/$', 'mysite.views.rss'),
  12. )

第二个

  1. # urls.py
  2. from django.conf.urls.defaults import *
  3. urlpatterns = patterns('',
  4. (r'^blog/', include('inner')),
  5. )
  6. # inner.py
  7. from django.conf.urls.defaults import *
  8. urlpatterns = patterns('',
  9. (r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
  10. (r'^about/$', 'mysite.views.about', {'blogid': 3}),
  11. (r'^rss/$', 'mysite.views.rss', {'blogid': 3}),
  12. )

这个例子和前面关于被捕获的参数一样(在上一节就解释过这一点),额外的选项将 总是 被传递到被包含的URLconf中的 每一 行,不管那一行对应的视图是否确实作为有效参数接收这些选项,因此,这个技术只有在你确实需要那个被传递的额外参数的时候才显得有用。 因为这个原因,这种技术仅当你确信在涉及到的接受到额外你给出的选项的每个URLconf时有用的才奏效。