django請求生命週期流程與路由層相關知識
請求生命週期流程圖
django請求生命週期流程圖
路由層之路由匹配
我們都知道,路由層是匹配對應關係用的,那麼它是怎麼匹配上的呢?
urlpatterns = [
url(r'^index/', views.index),
]
url方法的第一個引數其實是一個正則表示式,只要使用者輸入的地址字尾與內容匹配上,就會執行對應的檢視函式。
並且django有一個二次追加斜槓機制,如果你在輸入地址字尾時末尾沒有加斜槓,django會先匹配一次,如果匹配不上,那麼django還會讓瀏覽器預設加斜槓再次傳送請求,比如:
# 第一次匹配
http://127.0.0.1:8000/index
# 匹配不上加斜槓再次傳送請求
http://127.0.0.1:8000/index/
如果想要取消這個斜槓機制,那麼可以在settings.py加上:
APPEND_SLASH = False
因為是正則表示式,所以比如像上述程式碼中的例子,我在位址列輸入:
http://127.0.0.1:8000/index/abcde/66
或者:
http://127.0.0.1:8000/index/
都是可以匹配到正則:^index/ 的
拓展
讓使用者不需要輸入地址字尾就可以訪問到指定頁面:
urlpatterns = [ url(r'^$', views.index), ]
也可以定義一個尾頁, 使用者輸入一個沒有對應關係的直接返回:
urlpatterns = [
url(r'.*',views.error),
]
無名有名分組
無名分組
我們都知道,路由匹配成功之後就會呼叫檢視函式,並且預設情況下會自動給檢視函式傳遞一個request位置引數。
但是如果正則表示式中加了括號,那麼就不止傳遞一個request位置引數了,還會傳遞括號內正則表示式匹配到的內容。
urlpatterns = [
url(r'^index/(.*)', views.index),
]
如果正則加了一個括號,那麼檢視函式就需要多寫一個形參用於接收匹配到的內容,不然會報錯。
def index(request, aa):
return HttpResponse(aa)
這個就是無名分組。
有名分組
python中的正則表示式加括號是可以給括號內的內容進行命名的,這裡的正則表示式自然也可以。
給括號內的內容命名為address:
urlpatterns = [
url(r'^index/(?P<address>.*)', views.index),
]
給括號內命名後,檢視函式就需要一個名字相同的形參接收:
def index(request, address):
return HttpResponse(address)
這個就是有名分組。
補充說明
1.無名分組需要一個形參接收括號內的內容,名字隨意。
2.有名分組也需要一個形參接收括號內的內容,名字要與正則表示式裡的名字相同。
3.無名分組是位置傳參,有名分組是關鍵字傳參。
4.無名分組與有名分組不能混合使用,單個可以重複使用。
反向解析
前言:html中a標籤的href可以寫網址的全稱,也可以寫字尾,寫字尾會自動補全當前ip和port。
<a href='index'>點我跳轉index</a>
<!--href='127.0.0.1:8000/index' -->
如上述標籤可以跳轉到127.0.0.1:8000/index,但是如果我路由匹配表示式出現了變化,那麼這個地址就無法跳轉到我想要的頁面了,比如:
# 原本
url(r'^index/', views.index)
# 修改後
url(r'^index123/', views.index)
這個時候a標籤就失效了,這該如何解決呢?反向解析就可以解決這個問題。
反向解析
通過反向解析可以獲取到一個結果,該結果可以訪問到一個路由。這麼說可能有點模糊,我們來看實戰:
第一步:給對應關係起別名
url(r'^index/', views.index, name='index_view')
第二步:使用模板語法修改a標籤
<a href="{% url 'index_view' %}">點我跳轉index</a>
這個時候隨意修改路由的匹配表示式都會不出現a標籤無法跳轉。
後端也可以檢視‘index_view’對應的路由:
from django.shortcuts import reverse
reverse('index_view') # 對應路由
根據這個路由,我們也可以進行重定向:
from django.shortcuts import reverse
def index(request):
return redirect(reverse('index_view'))
無名有名分組反向解析
無名分組反向解析
如果你在設定路由時使用了無名分組,那麼你括號內的正則表示式的內容,需要人為指定。比如如下路由:
url(r'^index/(.*)', views.index, name='index_view')
這時候你的a標籤需要指定內容,因為對於表示式 '^index/(.*)' 有多種方式匹配到,a標籤不知道該使用哪個,所以需要人為指定。
比如我指定括號內的內容為:123
<a href="{% url 'index_view' 123 %}">點我跳轉index</a>
後端也需要指定:
from django.shortcuts import reverse
reverse('index_view', args=(123,)) # /index/123
有名分組反向解析
如果你在設定路由時使用了有名分組,那麼同理,需要人為指定內容。
路由:命名為address
url(r'^index/(?P<address>.*)', views.index, name='index_view')
a標籤:設定address為123,兩種方式都可
<a href="{% url 'index_view' 123 %}">點我跳轉index</a>
<a href="{% url 'index_view' address=123 %}">點我跳轉index</a>
後端:兩種方式都可
from django.shortcuts import reverse
reverse('index_view', args=(123,)) # /index/123
reverse('index_view', kwargs=('address':123)) # /index/123
路由分發
如果一個django專案特別龐大,裡面有很多應用,每個應用下有很多對應關係,這種情況如果把路由對應關係都寫在專案同名資料夾下的urls.py檔案下是明顯不合理的,所以我們要把路由對應關係拆分開。
django支援每個應用都可以有自己獨立的路由層、模板層、靜態檔案、檢視層(預設)、模型層(預設)。
每個應用編寫好自己的功能後,最後只需要整合一下就可以了。並且防止出現不同應用中出現相同路由,可以通過應用字首區分,並且用到一個include方法:
總路由:整個應用app01與app02
from django.conf.urls import url, include
# 匯入各個應用的路由,並起別名方便使用
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r'^app01/', include(app01_urls)),
url(r'^app02/', include(app02_urls)),
]
簡寫:
from django.conf.urls import url, include
urlpatterns = [
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
]
此時,訪問應用app01下的index就需要這麼輸入:
http://127.0.0.1:8000/app01/index/
名稱空間
不同的應用,設定路由時可能會使用相同的別名,比如:
應用app01路由:
urlpatterns = [
url(r'^index/', views.index, name='index_view'),
]
應用app02路由:
urlpatterns = [
url(r'^index/', views.index, name='index_view'),
]
a標籤:
<a href="{% url 'index_view' %}">點我跳轉index</a>
<a href="{% url 'index_view' %}">點我跳轉index</a>
此時我就無法讓我的a標籤都可以跳到應用app01下index或者應用app02下index,它只能跳轉到其中一個。
解決方法
方法一:總路由新增名稱空間
urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]
a標籤:
<a href="{% url 'app01:index_view' %}">點我跳轉index</a>
<a href="{% url 'app02:index_view' %}">點我跳轉index</a>
方式二:應用路由起別名加上應用字首,如
urlpatterns = [
url(r'^index/', views.index, name='app01_index_view'),
]
從根本解決問題。