Django 路由層

雲崖先生發表於2020-09-10

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-路由重定向

   關閉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的程式碼冗餘度,此外還可以進行非常給力的分組開發。

   image-20200909221712367

基本使用

   首先我們要在app01app02下建立兩個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
]

相關文章