在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ URL調(diào)度器
點(diǎn)擊劫持保護(hù)
安全問(wèn)題歸檔
Model 類參考
將遺留數(shù)據(jù)庫(kù)整合到Django
關(guān)聯(lián)對(duì)象參考
內(nèi)建基于類的視圖的API
聚合
Django 中的用戶認(rèn)證
django.contrib.humanize
Django管理文檔生成器
分頁(yè)
使用Django輸出CSV
加密簽名
文件儲(chǔ)存API
安全
Django中的測(cè)試
國(guó)際化和本地化
為Django編寫(xiě)首個(gè)補(bǔ)丁
條件表達(dá)式
日志
模型元選項(xiàng)
部署靜態(tài)文件
執(zhí)行查詢
使用Django認(rèn)證系統(tǒng)
基于類的視圖
中間件
編寫(xiě)自定義的django-admin命令
Django 的設(shè)置
格式本地化
數(shù)據(jù)庫(kù)訪問(wèn)優(yōu)化
錯(cuò)誤報(bào)告
基于類的內(nèi)建通用視圖
編寫(xiě)自定義存儲(chǔ)系統(tǒng)
編寫(xiě)你的第一個(gè) Django 程序 第3部分
編寫(xiě)數(shù)據(jù)庫(kù)遷移
使用表單
編寫(xiě)你的第一個(gè) Django 程序 第2部分
編寫(xiě)你的第一個(gè) Django 程序 第1部分
如何使用會(huì)話
系統(tǒng)檢查框架
新手入門(mén)
信號(hào)
編寫(xiě)視圖
如何使用WSGI 部署
編寫(xiě)你的第一個(gè)Django應(yīng)用,第6部分
常見(jiàn)的網(wǎng)站應(yīng)用工具
Widgets
內(nèi)建的視圖
模型實(shí)例參考
視圖層
Django中的密碼管理
高級(jí)教程:如何編寫(xiě)可重用的應(yīng)用
國(guó)際化和本地化
"本地特色"附加功能
TemplateResponse 和 SimpleTemplateResponse
模式編輯器
文件上傳
快速安裝指南
部署 Django
表單 API
表單素材 ( <code>Media</code> 類)
管理文件
其它核心功能
查找 API 參考
表單
Admin
數(shù)據(jù)庫(kù)函數(shù)
自定義查找
使用基于類的視圖處理表單
管理操作
開(kāi)發(fā)過(guò)程
編寫(xiě)你的第一個(gè)Django應(yīng)用,第5部分
進(jìn)行原始的sql查詢
模型層
多數(shù)據(jù)庫(kù)
編寫(xiě)你的第一個(gè) Django 程序 第4部分
Django安全
Django 初探
Django異常
重定向應(yīng)用
按需內(nèi)容處理
管理器
視圖裝飾器
驗(yàn)證器
使用Django輸出PDF
File對(duì)象
Django 的快捷函數(shù)
基于類的通用視圖 —— 索引
為模型提供初始數(shù)據(jù)
模板層
URL調(diào)度器
中間件
模型

URL調(diào)度器

簡(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ó)際化文檔。

Django 如何處理一個(gè)請(qǐng)求

當(dāng)一個(gè)用戶請(qǐng)求Django 站點(diǎn)的一個(gè)頁(yè)面,下面是Django 系統(tǒng)決定執(zhí)行哪個(gè)Python 代碼使用的算法:

  1. Django 決定要使用的根URLconf 模塊。通常,這個(gè)值就是ROOT_URLCONF 的設(shè)置,但是如果進(jìn)來(lái)的HttpRequest 對(duì)象具有一個(gè)urlconf 屬性(通過(guò)中間件request processing 設(shè)置),則使用這個(gè)值來(lái)替換ROOT_URLCONF 設(shè)置。
  2. Django 加載該P(yáng)ython 模塊并尋找可用的urlpatterns。它是django.conf.urls.url() 實(shí)例的一個(gè)Python 列表。
  3. Django 依次匹配每個(gè)URL 模式,在與請(qǐng)求的URL 匹配的第一個(gè)模式停下來(lái)。
  4. 一旦其中的一個(gè)正則表達(dá)式匹配上,Django 將導(dǎo)入并調(diào)用給出的視圖,它是一個(gè)簡(jiǎn)單的Python 函數(shù)(或者一個(gè)基于類的視圖)。視圖將獲得如下參數(shù):
    • 一個(gè)HttpRequest 實(shí)例。
    • 如果匹配的正則表達(dá)式?jīng)]有返回命名的組,那么正則表達(dá)式匹配的內(nèi)容將作為位置參數(shù)提供給視圖。
    • 關(guān)鍵字參數(shù)由正則表達(dá)式匹配的命名組組成,但是可以被django.conf.urls.url()的可選參數(shù)kwargs覆蓋。
  5. 如果沒(méi)有匹配到正則表達(dá)式,或者如果過(guò)程中拋出一個(gè)異常,Django 將調(diào)用一個(gè)適當(dāng)?shù)腻e(cuò)誤處理視圖。請(qǐng)參見(jiàn)下面的錯(cuò)誤處理。

例子

下面是一個(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),
]

注:

  • 若要從URL 中捕獲一個(gè)值,只需要在它周圍放置一對(duì)圓括號(hào)。
  • 不需要添加一個(gè)前導(dǎo)的反斜杠,因?yàn)槊總€(gè)URL 都有。例如,應(yīng)該是^articles 而不是 ^/articles。
  • 每個(gè)正則表達(dá)式前面的'r' 是可選的但是建議加上。它告訴Python 這個(gè)字符串是“原始的” —— 字符串中任何字符都不應(yīng)該轉(zhuǎn)義。參見(jiàn)Dive Into Python 中的解釋。

一些請(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á)式中的命名組和非命名組:

  1. 如果有命名參數(shù),則使用這些命名參數(shù),忽略非命名參數(shù)。
  2. 否則,它將以位置參數(shù)傳遞所有的非命名參數(shù)。

根據(jù)傳遞額外的選項(xiàng)給視圖函數(shù)(下文),這兩種情況下,多余的關(guān)鍵字參數(shù)也將傳遞給視圖。

URLconf 在什么上查找

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、GETHEAD等等 —— 都將路由到相同的函數(shù)。

捕獲的參數(shù)永遠(yuǎn)是字符串

每個(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ù)字符串。

指定視圖參數(shù)的默認(rèn)值

有一個(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ǔ)法

urlpatterns 應(yīng)該是url() 實(shí)例的一個(gè)Python 列表。

錯(cuò)誤處理

當(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。

包含其它的URLconfs

在任何時(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),
    ])),
]

捕獲的參數(shù)

被包含的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。

嵌套的參數(shù)

正則表達(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ù)。

傳遞額外的選項(xiàng)給視圖函數(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()

類似地,你可以傳遞額外的選項(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)。

URL 的反向解析

在使用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,然后可以雙向使用它:

  • 根據(jù)用戶/瀏覽器發(fā)起的URL 請(qǐng)求,它調(diào)用正確的Django 視圖,并從URL 中提取它的參數(shù)需要的值。
  • 根據(jù)Django 視圖的標(biāo)識(shí)和將要傳遞給它的參數(shù)的值,獲取與之關(guān)聯(lián)的URL。

第一種方式是我們?cè)谇懊娴恼鹿?jié)中一直討論的用法。第二種方式叫做反向解析URL、反向URL 匹配、反向URL 查詢或者簡(jiǎn)單的URL 反查。

在需要URL 的地方,對(duì)于不同層級(jí),Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url 模板標(biāo)簽。
  • 在Python 代碼中:使用django.core.urlresolvers.reverse() 函數(shù)。
  • 在更高層的與處理Django 模型實(shí)例相關(guān)的代碼中:使用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 模式。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 命名空間

簡(jiǎn)介

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' 中。

反查帶命名空間的URL

當(dāng)解析一個(gè)帶命名空間的URL(例如'polls:index')時(shí),Django 將切分名稱為多個(gè)部分,然后按下面的步驟查找:

  1. 首先,Django 查找匹配的應(yīng)用的命名空間(在這個(gè)例子中為'polls')。這將得到該應(yīng)用實(shí)例的一個(gè)列表。

  2. 如果有定義當(dāng)前 應(yīng)用,Django 將查找并返回那個(gè)實(shí)例的URL 解析器。當(dāng)前 應(yīng)用可以通過(guò)請(qǐng)求上的一個(gè)屬性指定。希望可以多次部署的應(yīng)用應(yīng)該設(shè)置正在處理的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è)定。

  1. 如果沒(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í)例)。

  2. 如果沒(méi)有默認(rèn)的應(yīng)用實(shí)例,Django 將該應(yīng)用挑選最后部署的實(shí)例,不管實(shí)例的名稱是什么。

  3. 如果提供的命名空間與第1步中的應(yīng)用命名空間 不匹配,Django 將嘗試直接將此命名空間作為一個(gè)實(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è)置,可以使用下面的查詢:

  • 如果其中一個(gè)實(shí)例是當(dāng)前實(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' %}

注意,在模板中的反查需要添加requestcurrent_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)
  • 如果沒(méi)有當(dāng)前實(shí)例 —— 如果我們?cè)谡军c(diǎn)的其它地方渲染一個(gè)頁(yè)面 —— '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è)。

URL 命名空間和被包含的URLconf

被包含的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。