django框架--路由系統
目錄
一、路由系統理解
系統功能:根據使用者訪問的不同 url
,執行對應的檢視函式。
web
伺服器可以根據使用者訪問的 url
地址的不同,返回相應的 html
頁面,而 html
的頁面渲染由檢視函式處理,這就需要有一個模組負責分析使用者訪問的 url
地址,並根據預先定義的對映規則,將請求分發到不同的檢視函式中進一步處理,負責這個工作的模組就是 web
框架中的路由系統。路由系統的工作總結起來就是: 制定路由規則,分析 url
,分發請求到響應檢視函式中 。
路由系統的路由功能基於路由表,路由表是預先定義好的 url
和檢視函式的對映記錄,換句話說,可以理解成將 url
和檢視函式做了繫結,對映關係有點類似一個 python
字典:
url_to_view_dic = { '路徑1': view_func_1, '路徑2': view_func_2, '路徑n': view_func_n, ... }
路由表的建立是控制層面,需要在實際業務啟動前就準備完畢,即:先有路由,後有業務。
一旦路由準備完畢,業務的轉發將會完全遵從路由表的指導:
去往路徑1的request --> 被路由器分發到view_func_1函式處理 去往路徑2的request --> 被路由器分發到view_func_2函式處理 去往路徑n的request --> 被路由器分發到view_func_n函式處理 ...
二、路由系統功能劃分
路由系統的本質功能是: 指路 ,針對一次路由請求,返回下一跳轉發地址。
任何路由系統都將涵蓋至少如下兩個核心功能:
路由器的核心功能:(非常重要!!!!)
1、建立路由表(控制層面) ----> 使用者定義
2、路由分發(轉發層面) ----> django框架自動處理
三、路由表建立
建立工具
django
框架中的工具: re_path
和 path
所有的 web
請求都將以 django
專案目錄下的 urls.py
檔案作為路由分發主入口,所以如果要完成最簡單的路由功能,只需要在此檔案中預先配置好路由表即可。 re_path
是 django v1
的工具, path
是 django v2
的工具,後者相容前者。
# 專案urls.py檔案, 目前兩種工具可以任選使用 re_path(r'home/', views.index) path('articles/<int:id>', views.show_article)
路由的匹配順序是 自上而下 ,一旦匹配即執行對應檢視函式,便 不再繼續匹配 。
所以路由表條目的順序很重要,有嚴格要求的路徑應該放前面,寬鬆要求甚至可以聚合的路徑應該放後面。匹配成功後的檢視函式以如下形式執行:
# 執行介面: view_func(request, *args, **kw) # 引數是固定的request物件以及由re_path或path捕獲的無名分組/有名分組引數 views.index(request) views.show_article(request, id)
如下是一張簡單的路由表配置:
# urls.py檔案 urlpatterns = [ # 自帶後臺管理頁面路由 path('admin/', admin.site.urls), # 新增 re_path(r'^add/author/$', views.add_author), re_path(r'^add/book/$', views.add_book), # 刪除 re_path(r'delete/author/(\d+)', views.delete_author), re_path(r'delete/book/(\d+)', views.delete_book), # 修改 re_path(r'edit/author/(\d+)', views.edit_author), re_path(r'edit/book/(\d+)', views.edit_book), ]
特別注意1, django
路由系統只會針對 url
進行匹配,並不會再額外考慮 method
或者其他 request
中的屬性,這也意味著僅僅只需考慮url即可。(當然,我覺得後續如有需要,可以增加匹配因子,以便做到更精準的匹配)
特別注意2,在瀏覽器中訪問某一個 url
,如果路徑結尾沒有新增 /
,在 django
框架中會被自動新增結尾的 /
。在路由表中,匹配路徑的時候要關注 /
,即: re_path(r'home/')
,換句話說,可以認為在 django
的環境下,路徑 pathinfo
是必須有後導 /
的。
二級路由
二級路由的意思就是把專案urls檔案中的路由整理劃分,分佈到各自的應用目錄 urls
檔案中,以此實現:
1、降低專案 urls
路由檔案中路由數量,由各自應用 urls
路由檔案承擔
2、解耦整個專案的路由表,出現路由問題的時候可以單獨在二級路由表中處理
3、多級路由以樹形結構執行查詢,在路由數量很大的時候,可以比單路由表有更快的查詢速度
用 include
實現二級路由表,二級路由會將在一級路由匹配到的 url
截斷後再發送給子路由表繼續匹配。以如下一級路由表為例,如果伺服器收到一個 http://www.xxx.com:8080/game/user/add/?name=a&pswd=b
的請求,首先會匹配一級路由表中的 game/
並將截斷後的 user/add/
傳送到二級路由表繼續匹配。
re_path(r'game/', include('game_app.urls')), re_path(r'chat/', include('chat_app.urls')), re_path(r'vidio/', include('vidio_app,urls'),
路由別名
因為路由 url
會被頻繁引用,所以會帶來修改時工作量過大的問題,解決辦法是啟用一個別名來代替 url
原始 url
,在所有引用的地方使用別名,這樣原始 url
不論如何修改,都會被正確指向。當然,這個前提是,別名不能發生修改,否則同樣要變動所有引用此別名的地方,所以別名的定義非常重要。此外,路由別名的作用域是全域性,它是一個全域性變數,這也意味著使用路由別名也有重名覆蓋的風險。
使用路由別名的目的是獲取原始 url
,如果原 url
有動態部分,需要在解析的時候傳入對應引數來明確動態部分。
路由別名重名覆蓋風險的解決方法:
1、在全域性urls
中定義每一個二級路由的
namespace
2、在每一個二級路由
urls
中定義
app_name
3、在別名定義的時候加上區分字首如: app01-home
, app02-home
別名的使用場景:
# 在模板中使用: {% url '別名' *args, **kw %} # 在檢視函式中使用: reverse('別名', *args, **kw)
動態路由及重定向
動態路由
所謂的動態路由,其實就是聚合大量同類的 url
,並用 re
規則執行匹配並獲取動態資料部分。
# re_path: re_path(r'articles/(?P<id>\d+)'), show_article)---> show_article(request, id=id) # path: path('articles/<int:id>', show_article) ---> show_article(request, id=id)
重定向
return redirect(某一個具體網址,可來自於反向解析的結果)
四、自定義錯誤頁面
固定流程如下:
settings.py
中
DEBUG
改為
False
,
ALLOWD_HOSTS
改為
['*']
templates
中新建對應的 404.html
, 500.html
等
urls
中定義:
handler404 = views.page_not_found handler500 = views.server_error
views
中配置對應函式:
def page_not_found(request): return render(request, '404.html') def server_error(request): return render(request, '500.html')
五、圖示路由系統在框架中的定位
每次請求到伺服器,執行路由的流程圖

虛擬碼實現以上圖示
# 啟動路由分發過程 def route(environ, route_table): url = environ.url view_func = None # 遍歷路由表 for map in route_table: if url == map[0]: view_func= map[1] break return view_func # 執行檢視函式處理過程 def start_handle(environ, view_func): if view_func: return view_func(environ) else: return page_not_found(environ) # web伺服器主迴圈 def run(): # 迴圈處理每一次的請求 while True: # 從tcp中獲取當前客戶端請求的http位元組資料 request_bytes = server.recv(1024) # 根據http協議解析,得到http資料 request_http_data = http_parse(request_bytes.decode('utf-8')) # web框架進一步處理http資料,封裝成方便使用的environ物件 environ = build_environ(request_http_data) # 根據當前請求的url,在路由表中找到對應的檢視函式 ---> 路由系統的工作介面 view_func = route(environ, route_table) # 啟動檢視函式,處理當前請求的具體內容, 返回處理結果 response = start_handle(environ, view_func) # 按照http協議拆解web框架封裝好的response物件,得到http字串 response_http_data = http_encapsulation(response) # 傳送http位元組資料給客戶端 server.send(response_http_data.encode('utf-8')) if __name__ == '__main__': run()
六、路由系統的進階想法
進階考慮:
路由器收到請求 request
後,轉發到後端另一臺機器上執行,然後使用協程非同步,處理其他的 reqeust
請求。如果請求得到的響應,再切換回協程,然後執行響應。這樣可以實現入口伺服器作為所有請求的承接者,然後轉發到對應的後面不同業務伺服器處理各自的業務,可以把業務分離到不同的機器上,而且此時入口伺服器也可以處理併發請求。
即:多個伺服器上均部署 django
,多臺伺服器之間的 django
可以相互通訊,這樣可以實現一個類似伺服器叢集的效果,可以完成負載均衡和備份的效果。
