我們在中級篇中學會瞭如何進行反向解析,但是有這樣一個問題,在為 url 命名的時候,名字不能重覆,否則會導致各種各樣的問題。在 url 還少的時候保證不重名還是比較簡單的,但是 url 多起來以後就比較難了。為瞭解決這樣的問題,可以在 url 中加一個首碼。例如,我有一個 url 的名字叫做 'co ...
我們在中級篇中學會瞭如何進行反向解析,但是有這樣一個問題,在為 url 命名的時候,名字不能重覆,否則會導致各種各樣的問題。在 url 還少的時候保證不重名還是比較簡單的,但是 url 多起來以後就比較難了。為瞭解決這樣的問題,可以在 url 中加一個首碼。例如,我有一個 url 的名字叫做 'comment' ,此時,我可以為其加一個首碼,這個首碼通常是 app 名,例如:'myapp-comment'。
這也是django所推薦的命名方式,但是這樣始終是治標不治本。此時,我們就要學習 django 中 url 命名空間了。
URL 命名空間
簡介:
URL 命名空間允許你反查到唯一的命名 URL,即使在不同的應用中使用相同的 URL 名稱。(也就是可以在不同的app中使用相同的名稱,為有命名困難症的程式員帶來了福音)
根據經驗,第三方應用應該始終使用帶命名空間的URL 。類似地,它還允許你在一個應用有多個實例部署的情況下反查URL。換句話講,因為一個應用的多個實例共用相同的命名URL,命名空間將提供一種區分這些命名 URL 的方法。
在一個站點上,正確使用 URL 命名空間的 Django 應用可以部署多次。例如,django.contrib.admin 具有一個 AdminSite 類,它允許你很容易地部署多個管理站點的實例。在下麵的例子中,我們將討論在兩個不同的地方部署教程中的polls 應用,這樣我們可以為兩種不同的用戶(作者和發佈者)提供相同的功能。
一個URL 命名空間有兩個部分,它們都是字元串:
- 應用命名空間:
- 它表示正在部署的應用的名稱。一個應用的每個實例具有相同的應用命名空間。例如,可以預見Django 的管理站點的應用命名空間是'admin'。
- 實例命名空間:
- 它表示應用的一個特定的實例。實例的命名空間在你的全部項目中應該是唯一的。但是,一個實例的命名空間可以和應用的命名空間相同。它用於表示一個應用的預設實例。例如,Django 管理站點實例具有一個預設的實例命名空間'admin'。
URL 的命名空間使用':' 操作符指定。例如,管理站點應用的主頁使用'admin:index'。它表示'admin' 的一個命名空間和'index' 的一個命名URL。
命名空間也可以嵌套。命名URL'sports:polls:index' 將在命名空間'polls'中查找'index',而poll 定義在頂層的命名空間'sports' 中。
反查帶命名空間的URL
我們在中級篇中瞭解到了 url 反查帶來的變數,而在中級篇中,都是使用 name 進行反查,這裡來看看如何對帶命名空間的 url 進行反查。
例子:
from django.conf.urls import include, url urlpatterns = [ url(r'^author-polls/', include('polls.urls', namespace='author-polls', app_name='polls')), url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls', app_name='polls')), ]
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'), ... ]
反查的方法和中級篇的一樣,在模板中:
{% url 'polls:index' %}
在基於類的視圖的方法中:
reverse('polls:index', current_app=self.request.resolver_match.namespace)
另外,註意,在模板中的反查需要添加 request 的 current_app 屬性,像這樣:
def render_to_response(self, context, **response_kwargs): self.request.current_app = self.request.resolver_match.namespace return super(DetailView, self).render_to_response(context, **response_kwargs)
這時,會有同學有疑問了, polls 這個應用命名空間設置了兩行呀,那 polls 下的 index 到底指的是哪個?
這個時候,就要看 django 的查找順序了:
1.如果當前有實例,也就是說我們通過 url 訪問到了某個處理函數,這個函數進行反向查詢的時候,例如我訪問的是:author-polls/ ,這個 url 對應的處理函數要進行反向解析,此時它要解析 'polls:detail'。那麼將解析到 author-polls/(?P<pk>\d+)/$ 中,也就是有實例的優先在該實例空間中查詢。
2.如果沒有實例,但是有預設的實例空間,例如 app_name='polls',namespace='polls' ,和應用空間同名,這樣的就叫做預設實例空間。在沒有訪問實例的時候,就匹配到預設實例空間中。
3.如果沒有實例,也沒有預設實例空間,那麼誰是最後註冊的就選誰,例子中的 namespace='publisher-polls' 就是最後一個註冊的(也就是下麵的)。
註意:
因為實例空間要是唯一的,所以使用 namespace:name 的模式應該也是唯一匹配的,例如這裡的'author-polls:index' 將永遠解析到 'author-polls' 實例的主頁('publisher-polls' 類似)。
URL 命名空間和被包含的URLconf
被包含的URLconf 的命名空間可以通過兩種方式指定。
首先,在你構造你的URL 模式時,你可以提供 應用 和 實例的命名空間給 include() 作為參數。例如
url(r'^polls/', include('polls.urls', namespace='author-polls', app_name='polls')),
這將包含 polls.urls 中定義的URL 到應用命名空間 'polls'中,其實例命名空間為'author-polls'。
其次,你可以include 一個包含嵌套命名空間數據的對象。如果你include() 一個url() 實例的列表,那麼該對象中包含的URL 將添加到全局命名空間。然而,你還可以include() 一個3個元素的元組:
(<list of url() instances>, <application namespace>, <instance namespace>)
註意這裡的應用命名空間和實例命名空間是相反的。
實例:
from django.conf.urls import include, url from . import views polls_patterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'), ] url(r'^polls/', include((polls_patterns, 'polls', 'author-polls'))),
這樣會包含命名的URL模式進入到給定的應用和實例命名空間中。
這裡來總結幾個關鍵函數的用法:
1. include(arg, namespace=None, app_name=None)
arg:可以接受一個字元串,表示被包含的模塊在哪裡;也可以接受一個列表,這個列表是被包含的 url() 的實例;還可以接受一個元祖,元祖的第一個元素是一個被包含的列表,第二個元素是該列表的應用空間名,第三個元素是實例空間名。
namespace : 實例命名空間
app_name : 應用命名空間
2. url(regex, view, kwargs=None, name=None, prefix='')
regex:要匹配的 url。
view:該 url 的處理函數,可以是一個表示函數位置的字元串, 也可以是一個函數的實例。
kwargs: 一個字典,表示傳遞多餘的參數。
name : 為 url 進行命名。
prefix : if prefix: view = prefix + '.' + view 表示在 view 前加上首碼。