URL 命名空间允许你使用唯一的反向命名URL模式( named URL patterns ),即便不同应用程序使用相同的 URL 名称。对于第三方应用程序来说,始终使用 URL 命名空间是个好习惯(像在教程里说的那样)。同样,如果已部署了应用程序的多个实例,它也允许你反向解析 URL。换句话说,因为单个应用的多个实例会分享已命名的 URL,命名空间提供了区分这些已命名 URL 的方法。
对于特定站点,正确使用URL名称空间的Django应用程序可以部署多次。比如 django.contrib.admin
有一个 AdminSite
,它允许admin实例部署多次。
URL 命名空间分为两部分,它们都是字符串:
这描述了正在部署的程序名。单个应用的每个实例拥有相同的命名空间。比如,Django admin 应用有可预测的应用命名空间 'admin'
。
这标识了应用程序的特定实例。实例命名空间应该是完整项目唯一的。但是实例命名空间可以和应用命名空间相同。这常用来指定应用的默认实例。比如,默认Django admin 实例拥有名为'admin'
的实例命名空间。
被指定的命名空间 URL 使用 ':'
操作符。比如,使用 'admin:index'
引用admin 应用的首页。这表明命名空间为 'admin'
,命名 URL 为 'index'
。
命名空间也可以嵌套。命名 URL 'sports:polls:index'
将在命名空间 'polls'
中寻找命名为 'index'
的模式,该模式是在顶层命名空间 'sports'
中定义的。
当给定一个命名空间 URL(例如 'polls:index'
)解析时,Django 会将完全限定的名称拆分成多个部分,然后尝试下面的查询:
application namespace
(这个例子里是 'polls'
)。这将产生应用实例列表。 reverse()
函数的 current_app
参数来指定当前应用程序。url 模板标签使用当前已解析的视图命名空间当作 RequestContext
中的应用程序。你可以通过设置在 request.current_app
属性上的当前应用来覆盖这个默认配置。polls
实例被称为 'polls'
)。 如果有嵌套的命名空间,则会对命名空间的每个部分重复这些步骤,直到视图名不被解析为止,然后视图名称将被解析为已找到的命名空间中的一个 URL 。
例如:
为了展示这个解决策略的实际作用,请考虑教程里 polls
应用程序的两个实例案例:分别被称为 'author-polls'
和 'publisher-polls'
。假设我们已经增强了这个应用程序,以便会在创建和显示 polls
时考虑实例命名空间
from django.urls import include, path
urlpatterns = [
path('author-polls/', include('polls.urls', namespace='author-polls')),
path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
...
]
使用这步后,可以进行以下查找:
如果我们在实例 'author-polls'
中渲染详情页 - 'polls:index'
将解析为 'author-polls'
的首页;比如下面两种都将触发 "/author-polls/"
。
在基于类的视图里的方法:
reverse('polls:index', current_app=self.request.resolver_match.namespace)
在模板中:
{% url 'polls:index' %}
如果我们在站点某处渲染一个页面 - 'polls:index'
将被解析为 polls
的最后一个注册实例。因为这里没有默认实例( 'polls'
的实例命名空间),所以将使用 polls
的最后一个注册实例。这将是 'publisher-polls'
,因为它是在 urlpatterns
的最后面声明的。
'author-polls:index'
会一直被解析为实例 'author-polls'
的首页(对于 'publisher-polls'
同样如此)。
如果还有一个默认实例 - 例如,一个叫 'polls'
的实例 - 唯一的变化就是没有当前实例(上面列表中的第二项)。在这个例子 'polls:index'
将解析为默认实例的首页而不是在 urlpatterns
中最后声明的实例。
有两种办法指定包含的URLconfs应用程序空间。
首先,你可以在包含的 URLcon 模块中设置一个 app_name
属性,在相同层作为 urlpatterns
属性。你必须传递实际的模块或对该模块的一个字符串引用传递给 include()
,而不是 urlpatterns
本身的列表。
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
...
]
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
]
polls.urls
里的 URLs 定义将具有应用程序命名空间 polls
。
其次,你可以包括一个包含嵌入式命名空间数据的对象。如果你 include()
了一个 path()
或 re_path()
实例的列表,那个对象里包含的 URLs 将被添加到全局命名空间内。但是,你也可以 include()
一个包含以下内容的2元组:
(<list of path()/re_path() instances>, <application namespace>)
例如:
from django.urls import include, path
from . import views
polls_patterns = ([
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
], 'polls')
urlpatterns = [
path('polls/', include(polls_patterns)),
]
这会将指定的 URL 模式包含到给定的应用程序命名空间里。
使用 include()
的 namespace
参数来指定实例命名空间。如果实例命名空间没有被指定,会默认已被导入的 URLconf 的应用程序命名空间。这意味着它也将成为那个命名空间的默认实例。