Django視圖層之路由配置系統(urls)
視圖層之路由配置系統(urls)
URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL與要為該URL調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。
‘‘‘ urlpatterns = [ url(正則表達式, views視圖函數,參數,別名), ] 參數說明: 一個正則表達式字符串 一個可調用對象,通常為一個視圖函數或一個指定視圖函數路徑的字符串 可選的要傳遞給視圖函數的默認參數(字典形式) 一個可選的name參數‘‘‘
正則字符串參數
1 簡單配置
from django.conf.urls import url from . import views urlpatterns = [
url(r‘^admin/‘, admin.site.urls), #系統生成的映射
url(r"^$",views.index), #訪問http://127.0.0.1:8000時,調用index視圖函數,根目錄地址訪問 url(r‘^articles/2003/$‘, views.special_case_2003), #表示articles/2003/這個路徑映射views模塊的special_case_2003函數url(r‘^articles/([0-9]{4})/$‘, views.year_archive), #表示匹配4個0-9的任意數字 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), ]
#註意:上面匹配都加了小括號,這些括號裏面的值會當作參數傳遞到後面的視圖函數中
‘‘‘ NOTE: 1 一旦匹配成功則不再繼續 2 若要從URL 中捕獲一個值,只需要在它周圍放置一對圓括號。3 不需要添加一個前導的反斜杠,因為每個URL 都有。例如,應該是^articles 而不是 ^/articles。 4 每個正則表達式前面的‘r‘ 是可選的但是建議加上。 一些請求的例子: /articles/2005/3/ 不匹配任何URL 模式,因為列表中的第三個模式要求月份應該是兩個數字。 /articles/2003/ 將匹配列表中的第一個模式而不是第二個,因為模式按順序匹配,第一個會首先測試是否匹配,匹配成功則不再進行匹配。 /articles/2005/03/ 請求將匹配列表中的第三個模式。
Django 將調用函數 views.month_archive(request, ‘2005‘, ‘03‘)。 按位置傳參 ‘‘‘
#設置項是否開啟URL訪問地址後面不為/跳轉至帶有/的路徑 APPEND_SLASH=TrueSLASH
2 有名分組(named group)
上面的示例使用簡單的、沒有命名的正則表達式組(通過圓括號)來捕獲URL 中的值並以位置 參數傳遞給視圖。在更高級的用法中,可以使用命名的正則表達式組來捕獲URL 中的值並以關鍵字 參數傳遞給視圖。
在Python 正則表達式中,命名正則表達式組的語法是(?P<name>pattern)
,其中name
是組的名稱,pattern
是要匹配的模式。
下面是以上URLconf 使用命名組的重寫:
from django.conf.urls import url from . 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/2005/03/ 請求將調用views.month_archive(request, year=‘2005‘, month=‘03‘)函數 /articles/2003/03/03/ 請求將調用函數views.article_detail(request, year=‘2003‘, month=‘03‘, day=‘03‘)。
在實際應用中,這意味你的URLconf 會更加明晰且不容易產生參數順序問題的錯誤 —— 你可以在你的視圖函數定義中重新安排參數的順序。當然,這些好處是以簡潔為代價;有些開發人員認為命名組語法醜陋而繁瑣。
如果給路徑命名了,那麽對應的視圖函數中,必須按照該命名作為形參。
註意:
無論正則表達式使用的是什麽匹配方式,每個捕獲的參數都作為一個普通的Python 字符串傳遞給視圖
例如,下面這行URLconf 中:
url(r‘^articles/(?P<year>[0-9]{4})/$‘, views.year_archive),
views.year_archive()
的year
參數將是一個字符串
3 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
等等 —— 都將路由到相同的函數。
4 指定視圖參數的默認值
有一個方便的小技巧是指定視圖參數的默認值。 下面是一個URLconf 和視圖的示例:
# 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"): ...
在上面的例子中,兩個URL模式指向同一個視圖views.page
—— 但是第一個模式不會從URL 中捕獲任何值。如果第一個模式匹配,page()
函數將使用num
參數的默認值"1"。如果第二個模式匹配,page()
將使用正則表達式捕獲的num
值。
別名
urlpatterns = [ url(r‘^reg/$‘, views.month_views,name=‘register‘), ]
而在訪問的靜態文件中,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <form method=‘post‘ action=‘{% register %}‘>xxxx</form> </body> </html>
當我們後端的路徑發生變化時(即匹配規則^reg/$需要改動時),直接改動,前端的頁面如果引用別名{% register %},則可不用改變前端任何代碼,都能夠正常映射訪問。
URL 的反向解析
獲取一個URL 最開始想到的信息是處理它視圖的標識(例如名字),查找正確的URL 的其它必要的信息有視圖參數的類型(位置參數、關鍵字參數)和值。
Django 提供一個辦法是讓URL 映射是URL 設計唯一的地方。你填充你的URLconf,然後可以雙向使用它:
- 根據用戶/瀏覽器發起的URL 請求,它調用正確的Django 視圖,並從URL 中提取它的參數需要的值。
- 根據Django 視圖的標識和將要傳遞給它的參數的值,獲取與之關聯的URL。
第一種方式是我們在前面的章節中一直討論的用法。第二種方式叫做反向解析URL、反向URL 匹配、反向URL 查詢或者簡單的URL 反查。
在需要URL 的地方,對於不同層級,Django 提供不同的工具用於URL 反查:
- 在模板中:使用url 模板標簽。
- 在Python 代碼中:使用
django.core.urlresolvers.reverse()
函數。 - 在更高層的與處理Django 模型實例相關的代碼中:使用
get_absolute_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‘), #... ]
根據這裏的設計,某一年nnnn對應的歸檔的URL是/articles/nnnn/
。
你可以在模板的代碼中使用下面的方法獲得它們:
<a href="{% url ‘news-year-archive‘ 2012 %}">2012 Archive</a> <ul> {% for yearvar in year_list %} <li><a href="{% url ‘news-year-archive‘ yearvar %}">{{ yearvar }} Archive</a></li> {% endfor %} </ul>
在Python 代碼中,這樣使用:
from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect def redirect_to_year(request): # ... year = 2006 # ... return HttpResponseRedirect(reverse(‘news-year-archive‘, args=(year,)))
如果出於某種原因決定按年歸檔文章發布的URL應該調整一下,那麽你將只需要修改URLconf 中的內容。
在某些場景中,一個視圖是通用的,所以在URL 和視圖之間存在多對一的關系。對於這些情況,當反查URL 時,只有視圖的名字還不夠。
命名URL 模式
為了完成上面例子中的URL 反查,你將需要使用命名的URL 模式。URL 的名稱使用的字符串可以包含任何你喜歡的字符。不只限制在合法的Python 名稱。
當命名你的URL 模式時,請確保使用的名稱不會與其它應用中名稱沖突。如果你的URL 模式叫做comment
,而另外一個應用中也有一個同樣的名稱,當你在模板中使用這個名稱的時候不能保證將插入哪個URL。
在URL 名稱中加上一個前綴,比如應用的名稱,將減少沖突的可能。我們建議使用myapp-comment
而不是comment
。
CBV
url(r‘^login.html$‘, views.Login.as_view()), ============================ from django.views import View class Login(View): def dispatch(self, request, *args, **kwargs): print(‘before‘) obj = super(Login,self).dispatch(request, *args, **kwargs) print(‘after‘) return obj def get(self,request): return render(request,‘login.html‘) def post(self,request): print(request.POST.get(‘user‘)) return HttpResponse(‘Login.post‘)View Code
路由應用分發
如果一個網站很多,有很多app應用,那麽就需要很多路由分發。如果將所有的路由分發都放在urlconf文件下,這樣會使得文件不易於管理,為此,我們可以給每一個app都創建一個urls.py文件,然後再urlconf中的urlpatterns中將該urls.py文件包含進來就行了。
from django.conf.urls import include, url # 導入全局url urlpatterns = [ url(r‘^blog‘, include(‘blog.urls‘)), #將訪問路徑以blog開頭的路徑分發到app1下的urls.py模塊裏進行路由映射 ]
這樣在我們blog-app中的url中,存放所有關於blog的url分發工作。
urlpatterns = [ url(r‘^2004/$‘, year_2004), url(r‘^(\d{4})/$‘, year_query), url(r‘^(\d{4})/(\d{2})$‘, year_query), url(r‘^(?P<year>\d{4})/(?P<month>\d{2})$‘, year_query), ]
這樣我們訪問網站應該是:http://127.0.0.1:8080/blog/2012/3 前面都得帶上app的名稱
Django視圖層之路由配置系統(urls)