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_pathpath
所有的web請求都將以django項目目錄下的urls.py文件作為路由分發主入口,所以如果要完成最簡單的路由功能,只需要在此文件中預先配置好路由表即可。re_pathdjango v1的工具,pathdjango 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.pyDEBUG改為FalseALLOWD_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可以相互通信,這樣可以實現一個類似服務器集群的效果,可以完成負載均衡和備份的效果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM