Django路由層
Django
路由層的功能就是匹配使用者的資源請求,通過資源匹配路徑來執行相應的檢視層功能。
路徑匹配
匹配順序
Django
中的資源請求路徑匹配是按照從上至下的順序進行。
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls), # ↓
url(r'^f1/', views.f1), # ↓
url(r'^f2/', views.f2), # ↓
url(r'^f3/', views.f3), # ↓
]
正則匹配
匹配方式為正則匹配,因此要注意使用^
與$
的使用。
由於匹配行為是從上至下,所以在定義時一定要注意順序。
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^f', views.f1),
url(r'^f', views.f2),
url(r'^f', views.f3),
]
# 無論輸入f幾,都是進入的f1的處理函式。
介紹兩個關於主頁和尾頁的匹配規則
主頁:
'^$'
此時直接訪問地址即可訪問成功尾頁:
''
注意放在最後,這代表沒匹配成功時將會彈出的資訊,可以定義一個404
的頁面進行返回。
重新匹配
如果第一次匹配沒匹配上,那麼在第二次匹配時Django
會要求瀏覽器對路徑進行加/
的處理重新再匹配一次,所以你將看到以下現象。
有兩次請求:
關閉Django
要求瀏覽器加/
的重新匹配行為,可在設定檔案中加上如下程式碼:
APPEND_SLASH = False # 預設為True
匹配分組
匹配分組常用於提取出請求資源地址上一些能夠被利用的資訊,如id
,日期等。
分組中的資料將以引數形式傳遞給檢視函式。
無名分組
單純的分組,不取名字即為無名分組。
注意:無名分組匹配到的組內容會當作位置引數傳遞給後面的檢視函式。
檢視層匹配規則
url(r'^date/(\d+)-(\d+)-(\d+)/$', views.date),
檢視層中的處理函式
def date(request,v1,v2,v3): # 位置與分組一一對應即可
return HttpResponse("{0}-{1}-{2}".format(v1,v2,v3))
請求的URL
http://127.0.0.1:8000/date/2020-01-28/
最終結果
2020-01-28
有名分組
有名分組即為分組取一個名字。
注意:有名分組匹配到的組內容會當作關鍵字引數傳遞給後面的檢視函式,這代表檢視函式中的引數與分組名字必須一致。
檢視層匹配規則
url(r'^date/(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+)/$', views.date),
檢視層中的處理函式
def date(request,year,month,day): # 必須與分組名相同
return HttpResponse("{0}-{1}-{2}".format(year,month,day))
請求的URL
http://127.0.0.1:8000/date/2020-01-28/
最終結果
2020-01-28
混合使用
需要注意的是Django
中不支援無名與有名分組的混合使用。
如果混合使用,無名分組將拿不到資料。
http://127.0.0.1:8000/date/2020-01-28/
url(r'^date/(\d+)-(?P<month>\d+)-(?P<day>\d+)/$', views.date),
def date(request,*args,**kwargs):
return HttpResponse("{0}-{1}".format(args,kwargs))
# ()-{'month': '01', 'day': '28'}
反向解析
為URL
匹配規則起一個別名,通過該別名可以轉換為請求資源路徑。
匹配別名
可以為匹配規則取一個別名,但是一定要注意!別名不能出現衝突。
url(r'^login/',views.login,name="login"),
前端解析
如果前端中都寫固定的請求資源路徑,那麼該路徑的匹配規則一改就都匹配不到了。
所以更推薦取別名來使用反向解析來進行操作。即點選<a>
標籤跳轉到test
檢視函式處理中。
無引數前端反向解析:
<a href="{% url 'test'%}">前端反向解析</a>
url(r'^test/',views.login,name="test"),
def test(request):
,,,
無名分組前端反向解析:
<a href="{% url 'test' 111 222 333 %}">前端反向解析(無名分組)</a> # 引數必須一一對應
url(r'^test/-(\d+)-(\d+)-(\d+)',views.login,name="test"),
def test(request,v1,v2,v3): # 引數必須一一對應
...
有名分組前端反向解析:
<a href="{% test 'login' 111 222 333 %}">前端反向解析(有名分組)</a> # 引數必須一一對應
url(r'^test/-(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+)',views.login,name="test"),
def test(request,year,month,day): # 引數必須一一對應
...
後端解析
後端的反向解析常用在跳轉中,如登陸完成後跳轉到首頁就可以使用後端反向解析。
後端使用反向解析,要先進行模組功能的匯入。
這是最常用的,後端無參反向解析。
from django.shortcuts import reverse
def login(request):
return redirect(reverse('index')) # 登入完成後跳轉到index頁面
url(r'^index/',views.index,name="index"), # 匹配規則,跳轉到index
def index(request):
...
如果後端反向解析的匹配規則中帶有無名分組,則需要使用args
關鍵字引數將引數帶上。
from django.shortcuts import reverse
def login(request):
return redirect(reverse('index',args=(111,222,333)))
url(r'^index/-(\d+)-(\d+)-(\d+)',views.index,name="index"), # 匹配規則,跳轉到index
def index(request,v1,v2,v3):
...
如果後端反向解析的匹配規則中帶有有名分組,則需要使用kwargs
關鍵字引數將引數帶上。
def login(request):
return redirect(reverse('index', kwargs={"year": 2020, "month": 12, "day": 28}))
url(r'^index/--(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+)',views.index,name="index"), # 匹配規則,跳轉到index
def index(request, year, month, day):
...
路由分發
Django
允許在每個APP
下擁有templates
資料夾,static
資料夾,當然也可以擁有urls.py
資料夾。
路由分發的作用在於緩解專案全域性資料夾下urls.py
的程式碼冗餘度,此外還可以進行非常給力的分組開發。
基本使用
首先我們要在app01
與app02
下建立兩個urls.py
。
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'f1/',views.f1,name="app01_f1")
]
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="app02_f1")
]
然後要在專案全域性資料夾下的urls.py
中匯入路由分發模組,然後匯入app01
以及app02
下的urls.py
。
from django.conf.urls import url
from django.conf.urls import 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)),
]
這樣在url
中輸入不同的字首就能訪問不同的APP
下對應的檢視功能。
http://127.0.0.1:8000/app01/f1/ # app01的urls處理該請求
http://127.0.0.1:8000/app02/f1/ # app02的urls處理該請求
快捷使用
基本的路由分發使用還需要在專案全域性資料夾下的urls.py
中匯入不同APP
中的urls.py
,這樣有點繁瑣。
其實可以直接如下程式碼這樣做更加簡便,都不用匯入不同APP
下的urls.py
了。
from django.conf.urls import url
from django.conf.urls import include # 匯入路由分發模組
urlpatterns = [
url(r'app01/', include('app01.urls')),
url(r'app02/', include('app02.urls')),
]
名稱空間
如果不同的APP
中,匹配別名相同則會造成名稱空間衝突的問題。
此時我們需要在專案總資料夾的urls.py
中對路由分發的路徑使用名稱空間,然後才可以使用反向解析。
reverse("f1") # 名稱空間衝突,始終解析的是app02下的f1
{% url 'f1' %}
# ======================================
from django.conf.urls import url
from django.conf.urls import include # 匯入路由分發模組
urlpatterns = [
url(r'app01/', include('app01.urls')),
url(r'app02/', include('app02.urls')), # 注意,app02在下面
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f1") # app01裡的f1
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f2") # app02裡的f1
]
reverse("app01:f1") # 反向解析時使用先拿到名稱空間,再那裡面的路徑別名
{% url 'app01:f1' %}
# ======================================
from django.conf.urls import url
from django.conf.urls import include # 匯入路由分發模組
urlpatterns = [
url(r'app01/', include('app01.urls',namespace="app01")), # 名稱空間 app01
url(r'app02/', include('app02.urls',namespace="app02")), # 名稱空間 app02
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f1") # app01裡的f1
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f2") # app02裡的f1
]