Django 路由層
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
//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
//127.0.0.1:8000/date/2020-01-28/
最終結果
2020-01-28
混合使用
需要注意的是Django
中不支援無名與有名分組的混合使用。
如果混合使用,無名分組將拿不到數據。
//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
下對應的視圖功能。
//127.0.0.1:8000/app01/f1/ # app01的urls處理該請求
//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
]