簡(jiǎn)潔、優(yōu)雅的URL 模式在高質(zhì)量的Web 應(yīng)用中是一個(gè)非常重要的細(xì)節(jié)。Django 允許你任意設(shè)計(jì)你的URL,不受框架束縛。
不要求有.php 或.cgi,更不會(huì)要求類似0,2097,1-1-1928,00 這樣無(wú)意義的東西。
參見(jiàn)萬(wàn)維網(wǎng)的發(fā)明者Berners-Lee 的Cool URIs don’t change,里面有關(guān)于為什么URL 應(yīng)該保持整潔和有意義的卓越的論證。
為了給一個(gè)應(yīng)用設(shè)計(jì)URL,你需要?jiǎng)?chuàng)建一個(gè)Python 模塊,通常稱為URLconf(URL configuration)。這個(gè)模塊是純粹的Python 代碼,包含URL 模式(簡(jiǎn)單的正則表達(dá)式)到Python 函數(shù)(你的視圖)的簡(jiǎn)單映射。
映射可短可長(zhǎng),隨便你。它可以引用其它的映射。而且,因?yàn)樗羌兇獾腜ython 代碼,它可以動(dòng)態(tài)構(gòu)造。
Django 還提供根據(jù)當(dāng)前語(yǔ)言翻譯URL 的一種方法。更多信息參見(jiàn)國(guó)際化文檔。
當(dāng)一個(gè)用戶請(qǐng)求Django 站點(diǎn)的一個(gè)頁(yè)面,下面是Django 系統(tǒng)決定執(zhí)行哪個(gè)Python 代碼使用的算法:
URLconf 模塊。通常,這個(gè)值就是ROOT_URLCONF 的設(shè)置,但是如果進(jìn)來(lái)的HttpRequest 對(duì)象具有一個(gè)urlconf 屬性(通過(guò)中間件request processing 設(shè)置),則使用這個(gè)值來(lái)替換ROOT_URLCONF 設(shè)置。urlpatterns。它是django.conf.urls.url() 實(shí)例的一個(gè)Python 列表。HttpRequest 實(shí)例。django.conf.urls.url()的可選參數(shù)kwargs覆蓋。下面是一個(gè)簡(jiǎn)單的 URLconf:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
注:
^articles 而不是 ^/articles。一些請(qǐng)求的例子:
/articles/2005/03/ 請(qǐng)求將匹配列表中的第三個(gè)模式。Django 將調(diào)用函數(shù)views.month_archive(request, '2005', '03')。/articles/2005/3/ 不匹配任何URL 模式,因?yàn)榱斜碇械牡谌齻€(gè)模式要求月份應(yīng)該是兩個(gè)數(shù)字。/articles/2003/ 將匹配列表中的第一個(gè)模式不是第二個(gè),因?yàn)槟J桨错樞蚱ヅ?,第一個(gè)會(huì)首先測(cè)試是否匹配。請(qǐng)像這樣自由插入一些特殊的情況來(lái)探測(cè)匹配的次序。/articles/2003 不匹配任何一個(gè)模式,因?yàn)槊總€(gè)模式要求URL 以一個(gè)反斜線結(jié)尾。/articles/2003/03/03/ 將匹配最后一個(gè)模式。Django 將調(diào)用函數(shù)views.article_detail(request, '2003', '03', '03')。上面的示例使用簡(jiǎn)單的、沒(méi)有命名的正則表達(dá)式組(通過(guò)圓括號(hào))來(lái)捕獲URL 中的值并以位置 參數(shù)傳遞給視圖。在更高級(jí)的用法中,可以使用命名的正則表達(dá)式組來(lái)捕獲URL 中的值并以關(guān)鍵字 參數(shù)傳遞給視圖。
在Python 正則表達(dá)式中,命名正則表達(dá)式組的語(yǔ)法是(?P<name>pattern),其中name 是組的名稱,pattern 是要匹配的模式。
下面是以上URLconf 使用命名組的重寫(xiě):
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
這個(gè)實(shí)現(xiàn)與前面的示例完全相同,只有一個(gè)細(xì)微的差別:捕獲的值作為關(guān)鍵字參數(shù)而不是位置參數(shù)傳遞給視圖函數(shù)。例如:
/articles/2005/03/ 請(qǐng)求將調(diào)用views.month_archive(request, year='2005', month='03')函數(shù),而不是views.month_archive(request, '2005', '03')。/articles/2003/03/03/ 請(qǐng)求將調(diào)用函數(shù)views.article_detail(request, year='2003', month='03', day='03')。在實(shí)際應(yīng)用中,這意味你的URLconf 會(huì)更加明晰且不容易產(chǎn)生參數(shù)順序問(wèn)題的錯(cuò)誤 —— 你可以在你的視圖函數(shù)定義中重新安排參數(shù)的順序。當(dāng)然,這些好處是以簡(jiǎn)潔為代價(jià);有些開(kāi)發(fā)人員認(rèn)為命名組語(yǔ)法丑陋而繁瑣。
下面是URLconf 解析器使用的算法,針對(duì)正則表達(dá)式中的命名組和非命名組:
根據(jù)傳遞額外的選項(xiàng)給視圖函數(shù)(下文),這兩種情況下,多余的關(guān)鍵字參數(shù)也將傳遞給視圖。
URLconf 在請(qǐng)求的URL 上查找,將它當(dāng)做一個(gè)普通的Python 字符串。不包括GET和POST參數(shù)以及域名。
例如,http://www.example.com/myapp/ 請(qǐng)求中,URLconf 將查找myapp/。
在 http://www.example.com/myapp/?page=3 請(qǐng)求中,URLconf 仍將查找myapp/。
URLconf 不檢查請(qǐng)求的方法。換句話講,所有的請(qǐng)求方法 —— 同一個(gè)URL的POST、GET、HEAD等等 —— 都將路由到相同的函數(shù)。
每個(gè)捕獲的參數(shù)都作為一個(gè)普通的Python 字符串傳遞給視圖,無(wú)論正則表達(dá)式使用的是什么匹配方式。例如,下面這行URLconf 中:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
... views.year_archive() 的year 參數(shù)將是一個(gè)字符串,即使[0-9]{4} 值匹配整數(shù)字符串。
有一個(gè)方便的小技巧是指定視圖參數(shù)的默認(rèn)值。 下面是一個(gè)URLconf 和視圖的示例:
# URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$', views.page),
url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]
# View (in blog/views.py)
def page(request, num="1"):
# Output the appropriate page of blog entries, according to num.
...
在上面的例子中,兩個(gè)URL模式指向同一個(gè)視圖views.page —— 但是第一個(gè)模式不會(huì)從URL 中捕獲任何值。如果第一個(gè)模式匹配,page() 函數(shù)將使用num參數(shù)的默認(rèn)值"1"。如果第二個(gè)模式匹配,page() 將使用正則表達(dá)式捕獲的num 值。
urlpatterns 中的每個(gè)正則表達(dá)式在第一次訪問(wèn)它們時(shí)被編譯。這使得系統(tǒng)相當(dāng)快。
urlpatterns 應(yīng)該是url() 實(shí)例的一個(gè)Python 列表。
當(dāng)Django 找不到一個(gè)匹配請(qǐng)求的URL 的正則表達(dá)式時(shí),或者當(dāng)拋出一個(gè)異常時(shí),Django 將調(diào)用一個(gè)錯(cuò)誤處理視圖。
這些情況發(fā)生時(shí)使用的視圖通過(guò)4個(gè)變量指定。它們的默認(rèn)值應(yīng)該滿足大部分項(xiàng)目,但是通過(guò)賦值給它們以進(jìn)一步的自定義也是可以的。
完整的細(xì)節(jié)請(qǐng)參見(jiàn)自定義錯(cuò)誤視圖。
這些值可以在你的根URLconf 中設(shè)置。在其它URLconf 中設(shè)置這些變量將不會(huì)生效果。
它們的值必須是可調(diào)用的或者是表示視圖的Python 完整導(dǎo)入路徑的字符串,可以方便地調(diào)用它們來(lái)處理錯(cuò)誤情況。
這些值是:
handler404 —— 參見(jiàn)django.conf.urls.handler404。handler500 —— 參見(jiàn)django.conf.urls.handler500。handler403 —— 參見(jiàn)django.conf.urls.handler403。handler400 —— 參見(jiàn)django.conf.urls.handler400。在任何時(shí)候,你的urlpatterns 都可以包含其它URLconf 模塊。這實(shí)際上將一部分URL 放置與其它URL 下面。
例如,下面是URLconf for the Django 網(wǎng)站自己的URLconf 中一個(gè)片段。它包含許多其它URLconf:
from django.conf.urls import include, url
urlpatterns = [
# ... snip ...
url(r'^community/', include('django_website.aggregator.urls')),
url(r'^contact/', include('django_website.contact.urls')),
# ... snip ...
]
注意,這個(gè)例子中的正則表達(dá)式?jīng)]有包含$(字符串結(jié)束匹配符),但是包含一個(gè)末尾的反斜杠。每當(dāng)Django 遇到include()(django.conf.urls.include())時(shí),它會(huì)去掉URL 中匹配的部分并將剩下的字符串發(fā)送給包含的URLconf 做進(jìn)一步處理。
另外一種包含其它URL 模式的方式是使用一個(gè)url() 實(shí)例的列表。例如,請(qǐng)看下面的URLconf:
from django.conf.urls import include, url
from apps.main import views as main_views
from credit import views as credit_views
extra_patterns = [
url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),
url(r'^charge/$', credit_views.charge),
]
urlpatterns = [
url(r'^$', main_views.homepage),
url(r'^help/', include('apps.help.urls')),
url(r'^credit/', include(extra_patterns)),
]
在這個(gè)例子中,/credit/reports/ URL將被 credit.views.report() 這個(gè)Django 視圖處理。
這種方法可以用來(lái)去除URLconf 中的冗余,其中某個(gè)模式前綴被重復(fù)使用。例如,考慮這個(gè)URLconf:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history),
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit),
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss),
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$', views.permissions),
]
我們可以改進(jìn)它,通過(guò)只聲明共同的路徑前綴一次并將后面的部分分組:
from django.conf.urls import include, url
from . import views
urlpatterns = [
url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([
url(r'^history/$', views.history),
url(r'^edit/$', views.edit),
url(r'^discuss/$', views.discuss),
url(r'^permissions/$', views.permissions),
])),
]
被包含的URLconf 會(huì)收到來(lái)之父URLconf 捕獲的任何參數(shù),所以下面的例子是合法的:
# In settings/urls/main.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
]
# In foo/urls/blog.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.blog.index),
url(r'^archive/$', views.blog.archive),
]
在上面的例子中,捕獲的"username"變量將被如期傳遞給包含的 URLconf。
正則表達(dá)式允許嵌套的參數(shù),Django 將解析它們并傳遞給視圖。當(dāng)反查時(shí),Django 將嘗試填滿所有外圍捕獲的參數(shù),并忽略嵌套捕獲的參數(shù)。考慮下面的URL 模式,它帶有一個(gè)可選的page 參數(shù):
from django.conf.urls import url
urlpatterns = [
url(r'blog/(page-(\d+)/)?$', blog_articles), # bad
url(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
]
兩個(gè)模式都使用嵌套的參數(shù),其解析方式是:例如blog/page-2/ 將匹配blog_articles并帶有兩個(gè)位置參數(shù)page-2/ 和2。第二個(gè)comments 的模式將匹配comments/page-2/ 并帶有一個(gè)值為2 的關(guān)鍵字參數(shù)page_number。這個(gè)例子中外圍參數(shù)是一個(gè)不捕獲的參數(shù)(?:...)。
blog_articles 視圖需要最外層捕獲的參數(shù)來(lái)反查,在這個(gè)例子中是page-2/或者沒(méi)有參數(shù),而comments可以不帶參數(shù)或者用一個(gè)page_number值來(lái)反查。
嵌套捕獲的參數(shù)使得視圖參數(shù)和URL 之間存在強(qiáng)耦合,正如blog_articles 所示:視圖接收URL(page-2/)的一部分,而不只是視圖感興趣的值。這種耦合在反查時(shí)更加顯著,因?yàn)榉床橐晥D時(shí)我們需要傳遞URL 的一個(gè)片段而不只是page 的值。
作為一個(gè)經(jīng)驗(yàn)的法則,當(dāng)正則表達(dá)式需要一個(gè)參數(shù)但視圖忽略它的時(shí)候,只捕獲視圖需要的值并使用非捕獲參數(shù)。
URLconfs 具有一個(gè)鉤子,讓你傳遞一個(gè)Python 字典作為額外的參數(shù)傳遞給視圖函數(shù)。
django.conf.urls.url() 函數(shù)可以接收一個(gè)可選的第三個(gè)參數(shù),它是一個(gè)字典,表示想要傳遞給視圖函數(shù)的額外關(guān)鍵字參數(shù)。
例如:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]
在這個(gè)例子中,對(duì)于/blog/2005/請(qǐng)求,Django 將調(diào)用views.year_archive(request, year='2005', foo='bar')。
這個(gè)技術(shù)在Syndication 框架 中使用,來(lái)傳遞元數(shù)據(jù)和選項(xiàng)給視圖。
處理沖突
URL 模式捕獲的命名關(guān)鍵字參數(shù)和在字典中傳遞的額外參數(shù)有可能具有相同的名稱。當(dāng)這種情況發(fā)生時(shí),將使用字典中的參數(shù)而不是URL 中捕獲的參數(shù)。
類似地,你可以傳遞額外的選項(xiàng)給include()。當(dāng)你傳遞額外的選項(xiàng)給include() 時(shí),被包含的URLconf 的每一 行將被傳遞這些額外的選項(xiàng)。
例如,下面兩個(gè)URLconf 設(shè)置功能上完全相同:
設(shè)置一次:
# main.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^blog/', include('inner'), {'blogid': 3}),
]
# inner.py
from django.conf.urls import url
from mysite import views
urlpatterns = [
url(r'^archive/$', views.archive),
url(r'^about/$', views.about),
]
設(shè)置兩次:
# main.py
from django.conf.urls import include, url
from mysite import views
urlpatterns = [
url(r'^blog/', include('inner')),
]
# inner.py
from django.conf.urls import url
urlpatterns = [
url(r'^archive/$', views.archive, {'blogid': 3}),
url(r'^about/$', views.about, {'blogid': 3}),
]
注意,額外的選項(xiàng)將永遠(yuǎn)傳遞給被包含的URLconf 中的每一行,無(wú)論該行的視圖實(shí)際上是否認(rèn)為這些選項(xiàng)是合法的。由于這個(gè)原因,該技術(shù)只有當(dāng)你確定被包含的URLconf 中的每個(gè)視圖都接收你傳遞給它們的額外的選項(xiàng)。
在使用Django 項(xiàng)目時(shí),一個(gè)常見(jiàn)的需求是獲得URL 的最終形式,以用于嵌入到生成的內(nèi)容中(視圖中和顯示給用戶的URL等)或者用于處理服務(wù)器端的導(dǎo)航(重定向等)。
人們強(qiáng)烈希望不要硬編碼這些URL(費(fèi)力、不可擴(kuò)展且容易產(chǎn)生錯(cuò)誤)或者設(shè)計(jì)一種與URLconf 毫不相關(guān)的專門(mén)的URL 生成機(jī)制,因?yàn)檫@樣容易導(dǎo)致一定程度上產(chǎn)生過(guò)期的URL。
換句話講,需要的是一個(gè)DRY 機(jī)制。除了其它有點(diǎn),它還允許設(shè)計(jì)的URL 可以自動(dòng)更新而不用遍歷項(xiàng)目的源代碼來(lái)搜索并替換過(guò)期的URL。
獲取一個(gè)URL 最開(kāi)始想到的信息是處理它視圖的標(biāo)識(shí)(例如名字),查找正確的URL 的其它必要的信息有視圖參數(shù)的類型(位置參數(shù)、關(guān)鍵字參數(shù))和值。
Django 提供一個(gè)辦法是讓URL 映射是URL 設(shè)計(jì)唯一的地方。你填充你的URLconf,然后可以雙向使用它:
第一種方式是我們?cè)谇懊娴恼鹿?jié)中一直討論的用法。第二種方式叫做反向解析URL、反向URL 匹配、反向URL 查詢或者簡(jiǎn)單的URL 反查。
在需要URL 的地方,對(duì)于不同層級(jí),Django 提供不同的工具用于URL 反查:
django.core.urlresolvers.reverse() 函數(shù)。get_absolute_url() 方法。例子
考慮下面的URLconf:
from django.conf.urls import url
from . import views
urlpatterns = [
#...
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
#...
]
根據(jù)這里的設(shè)計(jì),某一年nnnn對(duì)應(yīng)的歸檔的URL是/articles/nnnn/。
你可以在模板的代碼中使用下面的方法獲得它們:
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
在Python 代碼中,這樣使用:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
# ...
year = 2006
# ...
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
如果出于某種原因決定按年歸檔文章發(fā)布的URL應(yīng)該調(diào)整一下,那么你將只需要修改URLconf 中的內(nèi)容。
在某些場(chǎng)景中,一個(gè)視圖是通用的,所以在URL 和視圖之間存在多對(duì)一的關(guān)系。對(duì)于這些情況,當(dāng)反查URL 時(shí),只有視圖的名字還不夠。請(qǐng)閱讀下一節(jié)來(lái)了解Django 為這個(gè)問(wèn)題提供的解決辦法。
為了完成上面例子中的URL 反查,你將需要使用命名的URL 模式。URL 的名稱使用的字符串可以包含任何你喜歡的字符。不只限制在合法的Python 名稱。
當(dāng)命名你的URL 模式時(shí),請(qǐng)確保使用的名稱不會(huì)與其它應(yīng)用中名稱沖突。如果你的URL 模式叫做comment,而另外一個(gè)應(yīng)用中也有一個(gè)同樣的名稱,當(dāng)你在模板中使用這個(gè)名稱的時(shí)候不能保證將插入哪個(gè)URL。
在URL 名稱中加上一個(gè)前綴,比如應(yīng)用的名稱,將減少?zèng)_突的可能。我們建議使用myapp-comment 而不是comment。
URL 命名空間允許你反查到唯一的命名URL 模式,即使不同的應(yīng)用使用相同的URL 名稱。第三方應(yīng)用始終使用帶命名空間的URL 是一個(gè)很好的實(shí)踐(我們?cè)诮坛讨幸彩沁@么做的)。類似地,它還允許你在一個(gè)應(yīng)用有多個(gè)實(shí)例部署的情況下反查URL。換句話講,因?yàn)橐粋€(gè)應(yīng)用的多個(gè)實(shí)例共享相同的命名URL,命名空間將提供一種區(qū)分這些命名URL 的方法。
在一個(gè)站點(diǎn)上,正確使用URL 命名空間的Django 應(yīng)用可以部署多次。例如,django.contrib.admin 具有一個(gè)AdminSite 類,它允許你很容易地部署多個(gè)管理站點(diǎn)的實(shí)例。在下面的例子中,我們將討論在兩個(gè)不同的地方部署教程中的polls 應(yīng)用,這樣我們可以為兩種不同的用戶(作者和發(fā)布者)提供相同的功能。
一個(gè)URL 命名空間有兩個(gè)部分,它們都是字符串:
應(yīng)用命名空間
它表示正在部署的應(yīng)用的名稱。一個(gè)應(yīng)用的每個(gè)實(shí)例具有相同的應(yīng)用命名空間。例如,可以預(yù)見(jiàn)Django 的管理站點(diǎn)的應(yīng)用命名空間是'admin'。
實(shí)例命名空間
它表示應(yīng)用的一個(gè)特定的實(shí)例。實(shí)例的命名空間在你的全部項(xiàng)目中應(yīng)該是唯一的。但是,一個(gè)實(shí)例的命名空間可以和應(yīng)用的命名空間相同。它用于表示一個(gè)應(yīng)用的默認(rèn)實(shí)例。例如,Django 管理站點(diǎn)實(shí)例具有一個(gè)默認(rèn)的實(shí)例命名空間'admin'。
URL 的命名空間使用':' 操作符指定。例如,管理站點(diǎn)應(yīng)用的主頁(yè)使用'admin:index'。它表示'admin' 的一個(gè)命名空間和'index' 的一個(gè)命名URL。
命名空間也可以嵌套。命名URL'sports:polls:index' 將在命名空間'polls'中查找'index',而poll 定義在頂層的命名空間'sports' 中。
當(dāng)解析一個(gè)帶命名空間的URL(例如'polls:index')時(shí),Django 將切分名稱為多個(gè)部分,然后按下面的步驟查找:
首先,Django 查找匹配的應(yīng)用的命名空間(在這個(gè)例子中為'polls')。這將得到該應(yīng)用實(shí)例的一個(gè)列表。
request上的current_app 屬性。Changed in Django 1.8:
在以前版本的Django 中,你必須在用于渲染模板的每個(gè)`Context` 或 `RequestContext`上設(shè)置`current_app` 屬性。
當(dāng)前應(yīng)用還可以通過(guò)reverse() 函數(shù)的一個(gè)參數(shù)手工設(shè)定。
如果沒(méi)有當(dāng)前應(yīng)用。Django 將查找一個(gè)默認(rèn)的應(yīng)用實(shí)例。默認(rèn)的應(yīng)用實(shí)例是實(shí)例命名空間 與應(yīng)用命名空間 一致的那個(gè)實(shí)例(在這個(gè)例子中,polls 的一個(gè)叫做'polls' 的實(shí)例)。
如果沒(méi)有默認(rèn)的應(yīng)用實(shí)例,Django 將該應(yīng)用挑選最后部署的實(shí)例,不管實(shí)例的名稱是什么。
如果有嵌套的命名空間,將為命名空間的每個(gè)部分重復(fù)調(diào)用這些步驟直至剩下視圖的名稱還未解析。然后該視圖的名稱將被解析到找到的這個(gè)命名空間中的一個(gè)URL。
為了演示解析的策略,考慮教程中polls 應(yīng)用的兩個(gè)實(shí)例:'author-polls' 和'publisher-polls'。假設(shè)我們已經(jīng)增強(qiáng)了該應(yīng)用,在創(chuàng)建和顯示投票時(shí)考慮了實(shí)例命名空間。
#urls.py
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')),
]
#polls/urls.py
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'),
...
]
根據(jù)以上設(shè)置,可以使用下面的查詢:
author-polls' 實(shí)例的detail 頁(yè)面 —— 'polls:index' 將解析成'author-polls' 實(shí)例的主頁(yè)面;例如下面兩個(gè)都將解析成"/author-polls/"。在基于類的視圖的方法中:
reverse('polls:index', current_app=self.request.resolver_match.namespace)
和在模板中:
{% url 'polls:index' %}
注意,在模板中的反查需要添加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:index' 將解析到最后注冊(cè)的polls的一個(gè)實(shí)例。因?yàn)闆](méi)有默認(rèn)的實(shí)例(命名空間為'polls'的實(shí)例),將使用注冊(cè)的polls 的最后一個(gè)實(shí)例。它將是'publisher-polls',因?yàn)樗窃?code>urlpatterns中最后一個(gè)聲明的。author-polls:index' 將永遠(yuǎn)解析到 'author-polls' 實(shí)例的主頁(yè)('publisher-polls' 類似)。如果還有一個(gè)默認(rèn)的實(shí)例 —— 例如,一個(gè)名為'polls' 的實(shí)例 —— 上面例子中唯一的變化是當(dāng)沒(méi)有當(dāng)前實(shí)例的情況(上述第二種情況)。在這種情況下 'polls:index' 將解析到默認(rèn)實(shí)例而不是urlpatterns 中最后聲明的實(shí)例的主頁(yè)。
被包含的URLconf 的命名空間可以通過(guò)兩種方式指定。
首先,在你構(gòu)造你的URL 模式時(shí),你可以提供 應(yīng)用 和 實(shí)例的命名空間給include() 作為參數(shù)。例如:
url(r'^polls/', include('polls.urls', namespace='author-polls', app_name='polls')),
這將包含polls.urls 中定義的URL 到應(yīng)用命名空間 'polls'中,其實(shí)例命名空間為'author-polls'。
其次,你可以include 一個(gè)包含嵌套命名空間數(shù)據(jù)的對(duì)象。如果你include() 一個(gè)url() 實(shí)例的列表,那么該對(duì)象中包含的URL 將添加到全局命名空間。然而,你還可以include() 一個(gè)3個(gè)元素的元組:
(<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'))),
這將include 命名的URL 模式到給定的應(yīng)用和實(shí)例命名空間中。
例如,Django 的管理站點(diǎn)部署的實(shí)例叫AdminSite。AdminSite 對(duì)象具有一個(gè)urls 屬性:一個(gè)3元組,包含管理站點(diǎn)中的所有URL 模式和應(yīng)用的命名空間'admin'以及管理站點(diǎn)實(shí)例的名稱。你include()到你項(xiàng)目的urlpatterns 中的是這個(gè)urls 屬性。
請(qǐng)確保傳遞一個(gè)元組給include()。如果你只是傳遞3個(gè)參數(shù):include(polls_patterns, 'polls', 'author-polls'),Django 不會(huì)拋出一個(gè)錯(cuò)誤,但是根據(jù)include() 的功能,'polls' 將是實(shí)例的命名空間而'author-polls' 將是應(yīng)用的命名空間,而不是反過(guò)來(lái)的。
譯者:Django 文檔協(xié)作翻譯小組,原文:URLconfs。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。