Django URL(路由系統)
Django URL
URL配置(URLconf)就像 Django 所支撐網站的目錄。它的本質是URL模式以及要為該URL模式呼叫的檢視函式之間的對映表;就是以這種方式告訴Django,對於這個URL呼叫這段程式碼,對於那個URL呼叫那段程式碼。
一、URLconf
基本格式:
from django.conf.urls import url urlpatterns = [ url(正則表示式, views檢視函式,引數,別名), ]
引數說明:
- 正則表示式:一個正則表示式字串
- views檢視函式:一個可呼叫物件,通常為一個檢視函式或一個指定檢視函式路徑的字串
- 引數:可選的要傳遞給檢視函式的預設引數(字典形式)
- 別名:一個可選的name引數
注意:
Django 2.0 版本中的路由系統已改動(官方文件)
from django.urls import path urlpatterns = [ path('articles/2003/', views.special_case_2003), ]
二、正則表示式說明
from django.conf.urls import url from app_xx importviews 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), ]
注意:
- urlpatterns 中的元素按照書寫順序從上往下逐一匹配正則表示式,一旦匹配成功則不再繼續。
- 若要從URL中捕獲一個值,只需要在其周圍加上一對圓括號即可(分組匹配)。
- 不需要新增一個前導的反斜槓,因為每個URL 都有。例如,應該是 ^articles 而不是 ^/articles。
- 每個正則表示式前面的 'r' 是可選的,但是建議加上。
示例說明:
/articles/2005/03/ 與列表中的第三個條目匹配。Django會呼叫 views.month_archive(request, '2005', '03') /articles/2005/3/ 不匹配任何URL模式,因為列表中的第三個條目需要兩個月的數字 /articles/2003/ 將匹配列表中的第一個模式,而不是第二個模式。Django會呼叫 views.special_case_2003(request) /articles/2003 不匹配任何這些模式,因為每個模式都要求URL以斜槓結尾 /articles/2003/03/03/ 將匹配最終模式。Django會呼叫 views.article_detail(request, '2003', '03', '03')
補充說明:
APPEND_SLASH=False
settings.py 配置檔案中預設沒有 APPEND_SLASH 這個引數,但 Django 預設這個引數為 APPEND_SLASH = True 其作用就是自動在網址結尾加 /
三、命名組
上面的示例是使用簡單的正則表示式分組匹配(通過括號)來捕獲URL中的值,並將它們以位置引數形式傳遞給檢視。在更高階的用法中,可以使用命名的正則表示式組來捕獲URL位並將它們作為關鍵字引數傳遞給檢視。
在Python正則表示式中,命名正則表示式組的語法是 (?P<name>pattern) ,其中 name 是組的名稱,pattern 是要匹配的模式。
下面是以上 URLconf 使用命名組的重寫:
from django.conf.urls import url from app_xx import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ]
都是實現相同的功能,但有一點差別:捕獲的值作為關鍵字引數而不是位置引數傳遞給檢視函式
/articles/2018/11/ 這樣呼叫檢視函式 views.month_archive(request, year="2018", month="11")
實際上,使用分組命名匹配的方式可以使 URLconf 更加明晰,且不容易產生引數順序錯誤,但一些開發人員認為分組命名組語法難看且過於冗長;至於究竟應該使用哪一種,可以根據自己的喜好來決定。
四、URLconf搜尋的內容
URLconf 在請求的URL上查詢,將它當做一個普通的 Python 字串。這不包括GET或POST引數或域名。
在 http://www.example.com/myapp/ 請求中,URLconf 將查詢 myapp/
在 http://www.example.com/myapp/?page=3 請求中,URLconf 仍查詢 myapp/
URLconf 不檢查請求的方法。換句話說,所有的請求方法:同一個URL的 POST、GET、HEAD 等等,都將路由到相同的函式。
五、捕獲的引數總是字串
每個在 URLconf 中捕獲的引數,都作為一個普通的Python字串傳遞給檢視,無論正則表示式使用的是什麼匹配方式。例如:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
傳遞到檢視函式 views.year_archive() 中的 year 引數永遠是一個字串型別。
六、檢視函式中指定預設值
# urls.py中 from django.conf.urls import url from app_xx import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>[0-9]+)/$', views.page), ] # views.py中,可以為num指定預設值 def page(request, num="1"): pass
在上面的示例中,兩個URL模式都指向同一個檢視 views.page,但第一個模式不會從URL捕獲任何內容。如果第一個模式匹配,該 page() 函式將使用它的預設引數 num="1";如果第二個模式匹配,page() 函式
將使用正則表示式捕獲的 num 值。
七、include 其他的 URLconf
比如有多個app,每個app又有自己的urls,那麼專案裡的urls就相當於一級路由,各個app下的urls相當於二級路由。
那麼各個 app 下的 urls 設定示例如下:
# app_ss/urls.py中 from django.conf.urls import url from app_ss import views urlpatterns = [ url(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.articles), ]
專案下的 urls 設定示例如下:
from django.conf.urls import url,include from app_ss import urls as ss_urls from app_xx import urls as xx_urls urlpatterns = [ url(r'^app_ss/', include(ss_urls)), url(r'^app_xx/', include(xx_urls)), ]
什麼時候在路由系統中使用 include 呢?
專案裡有多個app(比如 car、house等),不同業務線使用不同的二級路由,方便管理。
示例演示:
127.0.0.1:8000/app_ss/articles/2018/10/
當訪問上面的URL時,會現在專案下的 urls.py 裡匹配 app_ss,當匹配成功時,就到 app_ss 應用下的 urls.py 裡匹配 articles/2018/10/ ,如果匹配成功,就執行檢視函式 views.articles(request, "year=2018", "month=10")
其他:
當 urlpatterns 中的正則匹配幾乎都一樣時,也可以使用 include 來刪除冗餘,如下:
八、傳遞額外的引數給檢視函式(瞭解)
URLconfs 有一個鉤子,允許一個 Python 字典作為額外的引數傳遞給檢視函式。
示例:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.articles, {'foo': 'bar'}), ]
在這個例子中,對於請求 /blog/2005/ 的URL,Django將呼叫 views.articles(request, year='2005', foo='bar')
在聯合框架中使用此技術,可以將元資料和選項傳遞給檢視。
九、URL反向解析
簡單來說就是可以給 URL 匹配規則起個名字,一個 URL 匹配模式一個名字。這樣以後就不需要寫死 URL 程式碼了,只需要通過名字來呼叫當前的URL。
# urls.py中
urlpatterns = [ url(r"^pd_car/", views.car, name="car"), url(r"^pd_house/", views.house, name="house"), ]
# views.py中 def car(request): return render(request, "pd_car.html") def house(request): return render(request, "pd_house.html")
還有兩個html頁面,即 pd_car.html 和 pd_house.html,在各自的 html 頁面中使用模板語法 {% url "別名" %} ,就可連結到對應的 URL 頁面中;如下面的程式碼那樣,而不是寫死的;比如,賣車頁面要跳轉到賣房頁面,寫死的格式就是這樣的 href="/pd_car/",所以不推薦這樣。
# pd_car.html中 <h1>賣車啦~~~</h1> <a href="{% url 'house' %}">點選進入:賣房</a> # pd_house.html中 <h1>賣房啦~~~</h1> <a href="{% url 'car' %}">點選進入:賣車</a>
總結:給每個 url 起別名,當 A 頁面要跳轉到 B 頁面的時候,就在 A 頁面用模板語法 {% url "B的別名" %} 即可
注意:
當要跳轉的 url 帶有引數的那種,比如:
url(r'^pd_car/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.car, name="car"), url(r'^pd_house/([0-9]{4})/([0-9]{2})/$', views.house, name="house"),
那麼在 html 中也要傳遞引數(還是上面那個例子):
# pd_car.html中 <h1>賣車啦~~~</h1> <a href="{% url "house" 2018 10 %}">點選進入:賣房</a> # pd_house.html中 <h1>賣房啦~~~</h1> <a href="{% url "car" year=2018 month=10 %}">點選進入:賣車</a>
views.py中也要給 url 對應的檢視函式傳遞引數,不然無法執行
def car(request,year,month): return render(request, "pd_car.html") def house(request,a,b): return render(request, "pd_house.html")