1 路由系統(urls控制)
url控制其實就是把不同的url對應到不同的views函數中去
格式:
# 項目目錄下的urls.py文件中
urlpatterns = [
url(regex, view, kwargs=None, name=None)
... ...
]
url可以有多個,每個url都是一個獨立的規則。
參數如下:
regex
(url正則表達式):與之匹配的 URL 會執行對應的第二個參數 view。view
(views視圖函數): 用於執行與正則表達式匹配的 URL 請求。kwargs
(參數列表): 視圖使用的字典類型的參數。 --> 很少使用name
(別名): 用來反向獲取 URL。
1.1 正則字符串參數
url的第一個參數為正則表達式,所以常用的正則表達式符號都可以進行匹配
from user import views # 導入我們的app的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), # 傳遞三個位置參數
]
這里對url表達式使用括號,表示取出匹配到的路徑字符串(分組)
注意:
- 一旦
匹配成功則不再繼續匹配
不需要添加一個前導的反斜杠
,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。- 每個正則表達式前面的'r',是可選的但是建議加上。
1.2 url的分組
在url正則表達式上加上括號,就表示對括號內的元素進行取出,然后傳給后面的views函數,根據傳遞參數的方式不同,分為無名分組
和有名分組
:
若要從URL中捕獲一個值,只需要在它周圍放置一對圓括號。
1.2.1 無名分組
只需要把要分組的正則字符串用括號括起來即可。這樣,括號內的匹配的內容會當作位置參數傳遞給后面指定的views函數。
urlpatterns = [
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.year_month),
]
# ([0-9]{4}) 第一個位置參數
# ([0-9]{2}) 第二個位置參數
views函數需要定義位置參數來一一對應,否則將會拋出TypeError異常
1.2.2 有名分組
即捕獲url中的一個值時,並賦予其名稱,使用關鍵字參數來進行傳遞。在Python 正則表達式中,命名正則表達式組的語法是(?P
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/(?P<year>201[0-9])', user.views.index)
]
# 會把 {'year':201[0-9]} 當作關鍵字參數
這種方式可以在views中的處理函數內,直接定義關鍵字變量來接受,而不用在意參數的位置。
def index(request,year):
... ...
如果year沒有捕獲到數據,那么views函數index將會報錯,所以我們一般可以在index中為year,配置默認值來避免這種錯誤。當然也可以在urls內,指定默認參數
url(r'^index/year(?P<year>[0-9]?)', user.views.index, {'year': 2019})
但是這樣就把前面匹配到的year的值給覆蓋了。請慎重選用
1.3 URLconf 在什么上查找
請求的URL被看做是一個普通的Python 字符串, URLconf在其上查找並匹配。進行匹配時將不包括GET或POST請求方式的參數以及域名。
- GET:把用戶發送的參數放在URL中進行傳遞,在URL中一般用?隔開。
- POST:把用戶發送的參數放在請求頭中傳遞。
例如:
- https://www.example.com/myapp/ 請求中,URLconf 將查找 myapp/
- https://www.example.com/myapp/?page=3 請求中,URLconf 仍將查找 myapp/ 。
URLconf 不檢查使用了哪種請求方法。換句話講,所有的請求方法,即對同一個URL的無論是 POST請求、GET請求、或是HEAD請求方法等等,都將路由到相同的函數。
1.4 include(路由分發)
當項目中的應用變得越來越多的時候,如果所有的應用的URL都通過項目的urls統一進行分配,那么耦合度會很高,另外也不利於管理,所以這里通過include來交給應用的urls來處理。
# 項目的urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^user/', include('user.urls')),
]
# 通過include 來指定交給那個應用的urls來處理
# include 包涵在 django.conf.urls中
在應用user下創建urls.py文件,寫入
from django.conf.urls import url
from user import views
urlpatterns = [
url('^login', views.login)
]
注意:路由分發后,子路徑的起始位置就從分發的URL開始了。上面匹配到的路徑為:user/login
1.5 別名(name參數)
當我們在做路徑匹配然后配合form表單等需要提交的數據的元素的時候會遇到以下問題
#urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login), # 匹配路徑
]
返回的頁面文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登錄頁面</h1>
<form action="/login/" method="post"> <!-- 根據路徑進行提交 -->
<p><h2>姓名</h2></p>
<p><input type="text" name="username"></p>
<p><h2>密碼</h2></p>
<p><input type="text" name="password"></p>
<p><input type="submit" value="登錄"></p>
</form>
</body>
</html>
如果我們某一天改了url匹配的路徑,那么,就緒要修改頁面中所有的提交路徑,否則將會提交失敗.而url的name就是解決這個問題的。
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/$', views.login,name='LOGIN'), # 添加name關鍵字
]
返回的html文件如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登錄頁面</h1>
<form action="{% url 'LOGIN' %}" method="post"> <!-- 這里使用name關鍵字來動態的傳遞url -->
<p><h2>姓名</h2></p>
<p><input type="text" name="username"></p>
<p><h2>密碼</h2></p>
<p><input type="text" name="password"></p>
<p><input type="submit" value="登錄"></p>
</form>
</body>
</html>
這樣就算URL后期更改,也會動態指向最新的URL。
- 個人覺得說白了就是一個變量的替換,只不過是用的是django特有的語法格式。
name='LOGIN' 就是把前面匹配的url保存到LOGIN中,然后Django 在返回html文件的時候再進行替換。
補充: - 當url存在正則表達式的時候,只使用name參數是不行的。因為正則部分無法進行渲染。目前的解決方法是在url部分進行拼接
# --------------------------- url ---------------------------
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^abc/(\d+)/', views.login,name="LOGIN"),
]
# -------------------------- Teamplates ---------------------------
<form action="{% url "LOGIN" 4 %}"> # 這里正則匹配了幾個部分,那么就需要傳遞幾個參數
<p>Username:</p>
<input type="text" name="username">
<p>Password:</p>
<input type="text" name="password">
<input type="submit" value="提交">
</form>
1.6 反推URL
什么叫反推url?在views函數中,如果想要獲取當前函數對應的url,該怎么辦呢?還記得前面的name屬性嗎,反推url就是在views中根據name屬性的值,獲得對應的url
from django.urls import reverse
url = reverse('name')
當然reverse還有兩個參數(args,kwargs)
args = ()
kwargs = {}
# 參數是配合urls中的正則表達式的
url('^detail/(\d+)' ,name='i1',views.detail) -- > reverse('i1',args=(10,))
# 反推的URL為: detail/10
# kwargs則表示在命名關鍵字的情況下
url('^detail/(?P<nid>\d+)' ,name='i2',views.detail) -- > reverse('i1',kwargs={'nid':10})
# 反推的url為: detail/10
還有一個方法是利用request對象的path_info,因為其中存放的是用戶提交的url。
1.7 命名空間
當在url(路由系統)中使用了include時,在views函數中,我們就無法單獨的利用name參數來反推url了,因為在include時,是無法使用name關鍵字的,不過django提供了其他關鍵字提供類似功能:namespace,稱作命名空間。
# urls.py
url = [
url(r'crm/',include('crm.urls'),namespace='crm'),
url(r'cmdb/',include('cmdb.urls'),namespace='cmdb'),
]
# crm 中的 urls.py
app_name = crm
url = [
url(r'index/',views.index,name='index'),
]
# crm 中的views.py
def test(request):
url = reverse('crm:index') # 這里通過namespace:name 來反向獲取url
print(url)
return HttpResponse(200)
PS:在html中,通過{% url 'crm:index' %} 也是通過namespace:name來獲取url的。