Handling HTTP requests 之URL dispatcher

綜述

設計一個web應用的URLs,你需要新建一個Python模塊來進行URL設置(URLconf)。這個模塊中純Python代碼的并且是一個URL patterns(正則表達式)與Python函數(views)之間的映射匹配。

Django完成一個網絡請求的過程。

<li>通常在setting.py文件中使用ROOT_URLCONF設置app的根URL,訪問的HttpRequest對象有一個屬性是urlconf,對應的值就是ROOT_URLCONF設置的值.
<li>Django加載上文中新建的模塊,并且尋找相應urlpatterns。urlpatterns是一個包含django.conf.urls.url()實例的列表。
<li>Django從上到下搜索每一個URL pattern,在第一個能夠匹配的url()實例出停止。
<li>一旦匹配成功Django就會倒入并且調用一個函數(或者是一個class-based view)返回一個視圖。獲取試圖的參數通過以下方式傳遞
<ol>
<li>通過HttpRequest實例傳遞。
<li>url()實例的正則表達式中傳遞參數
<li>django.conf.urls.url() 關鍵字傳遞參數
</ol>
<li>如果沒有匹配或者匹配過程中出現異常,Django將拋出異常

<pre>
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),
]
</pre>
<li>一個http:www.XXX/articles/2005/03/請求將會匹配第三個入口,Django將會調用views.month_archive(request, '2005', '03')函數
<li>/articles/2005/3/不會任何匹配,因為第三個入口中需要月份參數是兩位數。
<li>/articles/2003/將會匹配第一個模式而不是第二個。因為第一個匹配成功了,就不會繼續往下走
<li>/articles/2003不會有任何的匹配。上文中的每個pattern的結尾都必須要有一個"/"
<li>/articles/2003/03/03/ 匹配最后一個模式。并且調用views.article_detail(request, '2003', '03', '03')函數。

采用 name groups

采用正則表達式(?P<name>pattern)patter來匹配,捕獲的之作為關鍵之參數傳遞給視圖表達式。
<pre>
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),
]
</pre>

<li>/articles/2005/03/,將會調用 views.month_archive(request, year='2005', month='03')
<li>/articles/2003/03/03/ --->views.article_detail(request, year='2003', month='03', day='03')
同時傳遞給視圖函數的總是strings

URLconf結果

URLconf把一個requested URL當成一個普通的Python string搜索。與請求的方法無關(POST、GET)
https://www.example.com/myapp/ --->匹配 myapp/
https://www.example.com/myapp/?page=3 ----->匹配 myapp/ 參數可以通過視圖函數的request對象實例相關方法回去 request.GET['page']

指定默認值
<pre>

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.
...

在上面的例子中,兩個URL模式指向相同的視圖-views.page-。但是第一個模式并沒有從URL中捕捉到任何東西。如果第一個模式匹配,那么page()函數將使用它的默認參數num“1”。如果第二個模式匹配,page()將使用regex捕獲的任何num值
</pre>

Including other URLconfs

include() 函數,可以把urlpatterns放到別的地方去設置
<pre>
from django.conf.urls import include, url
urlpatterns = [
url(r'^community/', include('django_website.aggregator.urls')),
url(r'^contact/', include('django_website.contact.urls')),
]

把所有以community開頭的請求都交由django_website.aggregator.urls去處理
</pre>

也是一種拆分urlpatterns臃腫的辦法
<pre>
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/$', credit_views.report),
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)),
]

例子中/credit/reports/ 將有credit_views.report()處理。 現在 url(r'^credit/', include(extra_patterns))匹配,再在extra_patterns 尋找進一步的匹配
</pre>
include()參數的獲取
<pre>

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),
]

diyinqianchang/blog/archive/ --->views.blog.archive(request,username='diyinqianchang')

def archive(request,username=None)
</pre>

Reverse resolution of URLs

在編寫web程序時,有時候會需要在網頁上嵌入一個連接,用于跳轉。也可以用設計好的pattern來產生匹配格式的網址。
<li>在templates中使用此url的標記
<li>在Python代碼中reverse()函數 reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
<li> get_absolute_url()函數

name 標記
<pre>
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
]
<a href="{% url 'news-year-archive' 2015%}"></a>
</pre>

reverse()
<pre>
from django.urls import reverse
from django.http import HttpResponseRedirect
def redirect_to_year(request):
year = 2006
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
</pre>

URL命名空間

URL 命名空間允許你反查到唯一的,即使不同的應用使用相同的URL 名稱。第三方應用始終使用帶命名空間的URL 是一個很好的實踐。

當解析一個帶命名空間的URL(例如'polls:index')時,Django 將切分名稱為多個部分,然后按下面的步驟查找:
<li>首先,Django 查找匹配的 application namespace, 在下面的例子中為'polls'。這將得到該應用實例的一個列表。
<li>如果當前應用屬性被定義,Django將查找并返回那個實例的URL解析器。當前應用屬性可在reverse() 函數中通過current_app來指定。
<li>如果沒有當前應用。Django 將查找一個默認的應用實例。默認的應用實例是[instance namespace和application namespace 一致的那個實例(在下面例子中,polls的一個叫做'polls' 的實例)
<li>如果沒有默認的應用實例,Django 將挑選該應用最后部署的實例,不管實例的名稱是什么。
<li>如果提供的命名空間與第1步中的application namespace 不匹配,Django 將嘗試直接將此命名空間作為一個 instance namespace查找。

<pre>urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^author-polls/', include('polls.urls', namespace='author-polls')),
url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
</pre>

<pre>polls/urls.py
from django.conf.urls import url
from . import views
app_name = 'polls'
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
]
</pre>

本例中author-polls和publisher-polls都有相同連寫的主頁和詳細鏈接,被include() 在polls/urls.py

<li>如果其中一個實例是當前實例 —— 如果我們正在渲染'author-polls' 實例的detail 頁面 —— 'polls:index' 將解析成'author-polls' 實例的主頁面;例如下面兩個都將解析成"/author-polls/"。

<pre>第一和第二
reverse('polls:index', current_app=self.request.resolver_match.namespace)

{% url 'polls:index' %}
</pre>

<li>如果沒有當前實例——假如說我們在站點的其他地方渲染頁面——'polls:index'將解析到最后注冊到polls的實例。因為沒有默認的實例(實例命名空間為polls),將用注冊的polls的最后一個實例。它將是'publisher-polls',因為它是urlpatterns中最后一個聲明的.

<li>'author-polls:index' 將永遠解析到 'author-polls' 實例的主頁('publisher-polls' 類似) 沒有用什么命名空間,用name來標記

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容