咱們在中級篇中學會了如何進行反向解析,可是有這樣一個問題,在爲 url 命名的時候,名字不能重複,不然會致使各類各樣的問題。在 url 還少的時候保證不重名仍是比較簡單的,可是 url 多起來之後就比較難了。爲了解決這樣的問題,能夠在 url 中加一個前綴。例如,我有一個 url 的名字叫作 'comment' ,此時,我能夠爲其加一個前綴,這個前綴一般是 app 名,例如:'myapp-comment'。html
這也是django所推薦的命名方式,可是這樣始終是治標不治本。此時,咱們就要學習 django 中 url 命名空間了。前端
簡介:python
URL 命名空間容許你反查到惟一的命名 URL,即便在不一樣的應用中使用相同的 URL 名稱。(也就是能夠在不一樣的app中使用相同的名稱,爲有命名困難症的程序員帶來了福音)nginx
根據經驗,第三方應用應該始終使用帶命名空間的URL 。相似地,它還容許你在一個應用有多個實例部署的狀況下反查URL。換句話講,由於一個應用的多個實例共享相同的命名URL,命名空間將提供一種區分這些命名 URL 的方法。程序員
在一個站點上,正確使用 URL 命名空間的 Django 應用能夠部署屢次。例如,django.contrib.admin 具備一個 AdminSite 類,它容許你很容易地部署多個管理站點的實例。在下面的例子中,咱們將討論在兩個不一樣的地方部署教程中的polls 應用,這樣咱們能夠爲兩種不一樣的用戶(做者和發佈者)提供相同的功能。web
一個URL 命名空間有兩個部分,它們都是字符串:django
URL 的命名空間使用':' 操做符指定。例如,管理站點應用的主頁使用'admin:index'。它表示'admin' 的一個命名空間和'index' 的一個命名URL。併發
命名空間也能夠嵌套。命名URL'sports:polls:index' 將在命名空間'polls'中查找'index',而poll 定義在頂層的命名空間'sports' 中。app
咱們在中級篇中瞭解到了 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' 相似)。
被包含的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模式進入到給定的應用和實例命名空間中。
與 url 相關的函數都在 django.conf.urls 中,下面看看裏面都有哪些函數:
1. patterns(prefix, pattern_description, ...)
這是一個廢棄了的方法,在 django1.8 以前,urlpatterns 變量是該函數的實例。
例如:
from django.conf.urls import patterns, url urlpatterns = patterns('', url(r'^articles/([0-9]{4})/$', 'news.views.year_archive'), url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'news.views.month_archive'), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'news.views.article_detail'), )
第一個參數是一個前綴,這裏的全部表示處理函數的字符串都是以 'new.views' 開頭的,全部能夠改寫成下面這種形式:
from django.conf.urls import patterns, url urlpatterns = patterns('news.views', url(r'^articles/([0-9]{4})/$', 'year_archive'), url(r'^articles/([0-9]{4})/([0-9]{2})/$', 'month_archive'), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', 'article_detail'), )
由於 patterns 是python的一個方法,而 python 中,一個方法最多接受 255 個參數,也就是說最多能夠在一個 patterns 中寫 255-1 個 url,雖然這通常不會有什麼影響,由於咱們能夠經過 include 方法來分離 url,並且這個方法返回的是一個列表,因此能夠經過列表拼接的方式,來擴展,例如:
urlpatterns = patterns('', ... ) urlpatterns += patterns('', ... )
因此也只是如今最多一次性建立多少個 url 而已。
可是這個方法仍是在 1.8 中廢棄了(固然你還可強行用,到 1.9.4 爲止代碼並無被移除,之後的版本另算),之後直接使用 python 列表,列表中的元素是 url() 函數的實例就好了。而 python 的列表不限制長度,只看電腦的內存有沒有足夠的空間,因此也算是改進了。
2. static.static(prefix, view=django.views.static.serve, **kwargs)
若是你經過django的後臺上傳了一張圖片,而你又想在前端顯示它。通常而言 django 只提供了靜態文件的支持(默認是 /static/ 開頭的url請求都視爲靜態文件請求),而圖片上傳是經過 MEDIA_URL 來做爲
請求的開頭的,可是若是不作特殊設置,是沒法顯示的,此時,能夠經過如下的方式:
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # ... the rest of your URLconf goes here ... ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
這是老版本的寫法,新版本中直接把函數放進列表中,做爲列表中的一個元素就行。
注意:這裏咱們並無爲 view 傳參,直接用默認的就行。
固然,這也只是在開發環境中使用,若是到了正式生產環境,這些東西仍是老老實實用 web server ,例如Apache或者nginx之類的做爲前方代理,django自帶的 web 服務估計併發量在20左右就會掛掉,並且還不是守護進程,也就是說掛掉了不會重啓,要多蛋疼有多蛋疼。
3. include(arg, namespace=None, app_name=None)
arg:能夠接受一個字符串,表示被包含的模塊在哪裏;也能夠接受一個列表,這個列表是被包含的 url() 的實例;還能夠接受一個元祖,元祖的第一個元素是一個被包含的列表,第二個元素是該列表的應用空間名,第三個元素是實例空間名。
namespace : 實例命名空間
app_name : 應用命名空間
4. url(regex, view, kwargs=None, name=None, prefix='')
regex:要匹配的 url。
view:該 url 的處理函數,能夠是一個表示函數位置的字符串, 也能夠是一個函數的實例。
kwargs: 一個字典,表示傳遞多餘的參數。
name : 爲 url 進行命名。
prefix : if prefix: view = prefix + '.' + view 表示在 view 前加上前綴。
5.各類 handler:
django 自帶錯誤處理視圖:
handler400 = 'django.views.defaults.bad_request'
handler403 = 'django.views.defaults.permission_denied'
handler404 = 'django.views.defaults.page_not_found'
handler500 = 'django.views.defaults.server_error'
在觸發相應的錯誤的時候,都會轉向默認的處理函數,固然咱們也能夠重寫它們,只有在 urls.py 中導入它們,並改寫成咱們本身的處理函數的字符串表示就能夠了。