Python筆記:Django框架的URL的路由配置及原理

概述

  • 一個乾淨優雅的URL方案是高質量Web應用程序中的一個重要細節。
  • Django可以讓你自己設計URL,無論你想要什麼,沒有框架限制。
  • 要爲應用程序設計URL,您可以非正式地創建一個名爲URLconf(URL配置)的Python模塊。
  • 這個模塊是純Python代碼,是一個簡單的Python模式(簡單的正則表達式)到Python函數(您的視圖)之間的映射。
  • 備註:此文是基於Django1.11版本展開, 技術棧會有所升級,僅作參考!

Django處理請求

  • 當用戶從Django的站點請求頁面時,系統遵循以下步驟來執行的Python代碼
  • 首先Django確定要使用的根URLconf模塊,通過ROOT_URLCONF來設置,具體在settings.py配置文件中。
  • 但是如果傳入HttpRequest對象具有urlconf 屬性(由中間件設置),則其值將用於替換ROOT_URLCONF設置
  • Django加載該Python模塊並查找該變量urlpatterns, 這應該是一個Python的django.conf.urls.url()實例列表
  • Django按順序運行每個URL模式,並在匹配所請求的URL的第一個URL中停止
  • 一旦正則表達式匹配,Django將導入並調用給定的視圖,這是一個簡單的Python函數(或基於類的視圖), 該視圖通過以下參數傳遞:
    • 一個實例HttpRequest
    • 如果匹配的正則表達式沒有返回任何命名組,那麼來自正則表達式的匹配將作爲位置參數提供
    • 關鍵字參數由正則表達式匹配的任何命名組組成,由可選kwargs參數中指定的任何參數覆蓋 django.conf.urls.url()
  • 如果沒有正則表達式匹配,或者在此過程中的任何一點出現異常,Django將調用適當的錯誤處理視圖

URLconf的示例

from django.conf.urls import url
from . import views

'''
/articles/2005/03/將匹配列表中的第三個條目。Django會調用該函數 。views.month_archive(request, '2005', '03')
/articles/2005/3/ 不符合任何網址格式,因爲列表中的第三個條目需要兩個數字的月份。
/articles/2003/將匹配列表中的第一個模式,而不是第二個模式,因爲模式是按順序測試的,第一個模式是第一個測試通過。隨意利用這些命令插入特殊情況。在這裏,Django會調用該函數 views.special_case_2003(request)
/articles/2003 將不匹配任何這些模式,因爲每個模式要求URL以斜槓結尾。
/articles/2003/03/03/將匹配最終模式。Django會調用該函數。views.article_detail(request, '2003', '03', '03')
'''
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’正面的每個正則表達式字符串的中是可選的,但推薦使用。它告訴Python一個字符串是“raw” - 字符串中沒有任何內容應該被轉義。請參閱Dive Into Python的解釋。
  • 每個捕獲的參數都作爲純Python字符串發送到視圖,無論正則表達式的匹配是什麼,即使[0-9]{4}只會匹配整數字符串
  • 通過瀏覽器訪問服務: 注意:url路由,由上而下 進行匹配,如果在上面就匹配成功,則不會向下匹配
  • 具體響應步驟如下:
    通過瀏覽器訪問服務
        127.0.0.1:8000/abc ==>  root url(根路由) ==> 加載子路由(myweb/urls.py)
    
        ==> 正則匹配訪問的路徑(path) =-=> 視圖函數(views.index)
    
        ==> views.py index() 響應內容
    

關於URL命名組

  • 上述使用爲簡單實例,屬於正則表達式非命名組(通過括號)捕獲URL定位,並將它們作爲位置參數傳遞給視圖。
  • 在更高級的使用中,我們可以使用正則表達式命名組來捕獲URL定位,並將它們作爲關鍵字 參數傳遞給視圖。
  • 在Python正則表達式中,正則表達式命名組的語法是(?Ppattern),其中命名組中的命名就是name,並且 pattern是某些匹配的模式。

1 ) 示例

from django.conf.urls import url
from . import views

'''
請求/articles/2005/03/調用函數 ,。views.month_archive(request, year='2005', month='03') 而不是 views.month_archive(request, '2005', '03')
請求/articles/2003/03/03/調用函數 。views.article_detail(request, year='2003', month='03', day='03')
在實踐中,這意味着您的URLconfs稍微更明確,更不容易出現參數命令錯誤 - 您可以重新排序視圖的函數定義中的參數。
當然,這些好處是以簡潔爲代價的; 但是命名組語法太冗長。
'''

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),
]
  • 這完成了與上一個例子完全相同的事情,有一個微妙的區別:捕獲的值被傳遞到視圖函數作爲關鍵字參數,而不是位置參數

2 ) URLconf的搜索

  • URLconf將根據所請求的URL進行搜索,作爲普通的Python字符串。這不包括GET或POST參數或域名

    • 在請求中https://www.example.com/app/, URLconf將尋找app/
    • 在請求中https://www.example.com/app/?page=3, URLconf將會查找app/
  • URLconf不查看請求方法。換句話說,所有的請求方法(GET,POST,HEAD等)都將被路由到相同的URL功能

3 ) 指定用於視圖參數的默認值

  • 一個方便的技巧是爲您的視圖參數指定默認參數。下面是一個URLconf和view的例子:
  • 在下面的示例中,兩個URL模式指向相同的視圖views.page, 但是第一個模式不會從URL捕獲任何內容
    • 如果第一個模式匹配,該page() 函數將使用它的默認參數num,“1”
    • 如果第二個模式匹配,page() 將使用num正則表達式捕獲的任何值, 示例:
    # URLconf
    from django.conf.urls import url
    from . import views
    
    urlpatterns = [
        url(r'^blog/$', views.page),
        url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
    ]
    
    # View (in blog/views.py)
    def page(request, num="1"):
        # Output the appropriate page of blog entries, according to num.
        ...
    

3 ) 錯誤處理

  • 當Django找不到與請求的URL匹配的正則表達式時,或者異常引發時,Django將調用錯誤處理視圖。
  • 用於這些情況的視圖由四個變量指定。它們的默認值對於大多數項目都是足夠的,但通過覆蓋其默認值可以進一步定製。
  • 有關詳細信息,請參閱自定義錯誤視圖的文檔。
  • 這樣的值可以在你的根URLconf中設置。在任何其他URLconf中設置這些變量將不起作用。
  • 值必須是可調用的,或者代表視圖的完整的Python導入路徑的字符串,應該被調用來處理手頭的錯誤條件。
  • 相關變量說明:
    • handler400- 見django.conf.urls.handler400
    • handler403- 見django.conf.urls.handler403
    • handler404- 見django.conf.urls.handler404
    • handler500- 見django.conf.urls.handler500

4 ) 關於404錯誤

  • 在開發階段無需考慮404的錯誤,但是在生產階段, 需要特別處理一下
  • 在項目下新建一個tpls模板目錄: tpls
  • 404的錯誤頁面,在模板目錄中創建一個404.html的頁面
  • 在配置文件中 settings.py 中 TEMPLATES 中的DIRS中添加os.path.join(BASE_DIR, 'tpls')
  • 在配置文件中 settings.py 中 DEBUG=False, 在出現404的情況時,自動配置的404頁面
  • 也可以在視圖函數中 手動報出404錯誤,帶提醒信息
    # 注意 Http404需要在django.http的模塊中引入
    # 響應404
    raise Http404('出錯了!')
    
  • 在模板中 404.html, 示例:
    <!DOCTYPE html>
    <html>
    <head>
        <title>404</title>
    </head>
    <body>
        <center>
            <h2>404 not found</h2>
            <h3>{{ exception }}</h3>
        </center>
    </body>
    </html>
    

5 ) 包括其他的URLconf

  • 在任何時候,urlpatterns都可以“包含”其他URLconf模塊。
  • 這實質上是將一組網址“植根於”其他網址之下
  • 例如,下面是Django網站本身的URLconf的摘錄。它包含許多其他URLconf:
    from django.conf.urls import include, url
    
    urlpatterns = [
        # ... snip ...
        url(r'^community/', include('django_website.aggregator.urls')),
        url(r'^contact/', include('django_website.contact.urls')),
        # ... snip ...
    ]
    
  • 請注意,此示例中的正則表達式沒有$(字符串尾匹配字符),但包含尾部斜線。
  • 每當Django遇到include()(django.conf.urls.include())時,它會截斷與該點匹配的URL的任何部分,並將剩餘的字符串發送到包含的URLconf以供進一步處理。

6 ) URL的反向解析

  • 如果在視圖、模板中使用硬編碼的鏈接,在urlconf發生改變時,維護是一件非常麻煩的事情

    • 解決:在做鏈接時,通過指向urlconf的名稱,動態生成鏈接地址
    • 視圖:使用django.core.urlresolvers.reverse()函數
    • 模板:使用url模板標籤
  • 示例:在URLconf中

    from django.conf.urls import url
    from . import views
    
    urlpatterns = [
        #...
        url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
        #...
    ]
    
  • 您可以使用以下模板代碼獲取這些:

    <a href="{ %   url 'news-year-archive' 2012   % }">2012 Archive</a>
        {# Or with the year in a template context variable: #}
    <ul>
        { %   for yearvar in year_list   % }
            <li><a href="{ %   url 'news-year-archive' yearvar   % }">{ {   yearvar   } } Archive</a></li>
        { %   endfor   % }
    </ul>
    
  • 在Python代碼中:

    from django.urls import reverse
    from django.http import HttpResponseRedirect
    
    def redirect_to_year(request):
        # ...
        year = 2006
        # ...
        return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
    

    或簡寫爲:

    from django.shortcuts import redirect
    from django.core.urlresolvers import reverse
    
    def index(request):
        year = 2006
        return redirect(reverse('ews-year-archive',args=(year,)))
    
發佈了410 篇原創文章 · 獲贊 221 · 訪問量 69萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章