路由系統
路由系統概念
簡而言之,路由系統就是路徑和視圖函數的一個對應關系。
django的路由系統作用就是使views里面處理數據的函數與請求的url建立映射關系。使請求到來之后,根據urls.py里的關系條目,去查找到與請求對應的處理方法,從而返回給客戶
端http頁面數據
路由系統的格式
url(正則表達式,view視圖函數/視圖類,參數)
django 項目中的url規則定義放在project 的urls.py目錄下,
默認如下:
from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), ]
url()函數可以傳遞4個參數,其中2個是必須的:regex和view,以及2個可選的參數:kwargs和name。下面是具體的解釋:
- regex:
regex是正則表達式的通用縮寫,它是一種匹配字符串或url地址的語法。Django拿着用戶請求的url地址,在urls.py文件中對urlpatterns列表中的每一項條目從頭開始進行逐一對比,
一旦遇到匹配項,立即執行該條目映射的視圖函數或二級路由,其后的條目將不再繼續匹配。因此,url路由的編寫順序至關重要!
需要注意的是,regex不會去匹配GET或POST參數或域名,例如對於https://www.example.com/myapp/,regex只嘗試匹配myapp/。對於https://www.example.com/myapp/?page=3,regex也只嘗試匹配myapp/。
如果你想深入研究正則表達式,可以讀一些相關的書籍或專論,但是在Django的實踐中,你不需要多高深的正則表達式知識。
性能注釋:正則表達式會進行預先編譯當URLconf模塊加載的時候,因此它的匹配搜索速度非常快,你通常感覺不到。
-
view:
當正則表達式匹配到某個條目時,自動將封裝的HttpRequest對象作為第一個參數,正則表達式“捕獲”到的值作為第二個參數,傳遞給該條目指定的視圖。如果是簡單捕獲,那么捕獲值將作
為一個位置參數進行傳遞,如果是命名捕獲,那么將作為關鍵字參數進行傳遞。 -
kwargs:
任意數量的關鍵字參數可以作為一個字典傳遞給目標視圖。
-
name:
對你的URL進行命名,可以讓你能夠在Django的任意處,尤其是模板內顯式地引用它。相當於給URL取了個全局變量名,你只需要修改這個全局變量的值,在整個Django中引用它的地方也將
同樣獲得改變。這是極為古老、朴素和有用的設計思想,而且這種思想無處不在。
1.最基礎映射
用戶訪問http://127.0.0.1:8000/index 然后后端使用index()函數處理(簡單來說就是硬性匹配,寫的什么就去匹配什么,沒有一點回旋余地)
urls.py from django.conf.urls import include, url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/$', views.index), ]
1、先從創建的app下的views.py面定義處理數據的函數
2、在urls.py里導入views
3、在urlpatterns里寫入一條url與處理函數的l映射關系
4、url映射一般是一條正則表達式,“^” 字符串的開始,“$“ 字符串的結束
5、當寫成\^$不輸入任何url時不會在返回黃頁,而是返回后面函數里對應的頁面。一般這一條會寫在url的最后。如
2.按照順序放置的動態路由
可以使用正則來匹配URL,將一組url使用一條映射搞定
urlpatterns = [ url(r'^host/(\d+)$', views.host), url(r'^host_list/(\d+)/(\d+)$', views.host_list), ]
\^host/(\d+)$
相對應的url是: ”http://127.0.0.1/host/2“ (\d+)是匹配任意的數字,在分頁時靈活運用。
在views.host中需要指定一個形式參數來接受(\d+)\$ 的值
def user_list(request,id): return HttpResponse(id)
\^host_list/(\d+)/(\d+)$
相對應的url是: ”http://127.0.0.1/host/8/9“,匹配到的數字會以參數的形式按照順序傳遞給views里面相對應的函數
在views.host_list中需要指定兩個形式參數,注意:此參數的順序嚴格按照url中匹配的順序
def user_list(request,hid,hid2): return HttpResponse(hid+hid2)
3.傳參形勢的路由
利用正則表達式的分組方法,將url以參數的形式傳遞到函數,可以不按順序排列
urlpatterns = [ url(r'^user_list/(?P<v1>\d+)/(?P<v2>\d+)$',views.user_list), ]
(?P<v1>\d+) 正則表達式的分組,相當於一個字典, key=v1, value=\d+。 {"v1":"\d+"}
然后將此參數傳遞到views里對應的函數,可以不按照順序
def user_list(request,v2,v1): return HttpResponse(v1+v2) 參數v1 = (?P<v1>\d+) 參數v2 = (?P<v2>\d+)
4.根據不同的app來分發不同的url(include方法)
如果一個項目下有很多的app,那么在urls.py里面就要寫巨多的urls映射關系。這樣看起來很不靈活,而且雜亂無章。
我們可以根據不同的app來分類不同的url請求。
首先,在urls.py里寫入urls映射條目。注意要導入include方法
from django.conf.urls import include, url from django.contrib import admin from app01 import app01_urls
from app02 import app02_urls
urlpatterns = [ url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ]
這條關系的意思是將url為”app01/“的請求都交給app01下的urls去處理
其次,在app01下創建一個urls.py文件,用來處理請求的url,使之與views建立映射
from django.conf.urls import include, url from app01 import views urlpatterns = [ url(r'index/$', views.index), ]
想對於url請求為: "http://127.0.0.1/app01/index/"
5.通過反射機制,為django開發一套動態的路由系統
在urls.py里定義分類正則表達式
from django.conf.urls import patterns, include, url from django.contrib import admin from DynamicRouter.activator import process urlpatterns = patterns('', # Examples: # url(r'^$', 'DynamicRouter.views.home', name='home'), # url(r'^blog/', include('blog.urls')), url(r'^admin/', include(admin.site.urls)), ('^(?P<app>(\w+))/(?P<function>(\w+))/(?P<page>(\d+))/(?P<id>(\d+))/$',process), ('^(?P<app>(\w+))/(?P<function>(\w+))/(?P<id>(\d+))/$',process), ('^(?P<app>(\w+))/(?P<function>(\w+))/$',process), ('^(?P<app>(\w+))/$',process,{'function':'index'}), )
在同目錄下創建activater.py
from django.shortcuts import render_to_response,HttpResponse,redirect def process(request,**kwargs): '''接收所有匹配url的請求,根據請求url中的參數,通過反射動態指定view中的方法''' app = kwargs.get('app',None) function = kwargs.get('function',None) try: appObj = __import__("%s.views" %app) viewObj = getattr(appObj, 'views') funcObj = getattr(viewObj, function) #執行view.py中的函數,並獲取其返回值 result = funcObj(request,kwargs) except (ImportError,AttributeError),e: #導入失敗時,自定義404錯誤 return HttpResponse('404 Not Found') except Exception,e: #代碼執行異常時,自動跳轉到指定頁面 return redirect('/app01/index/') return result
6.FBV和CBV
所謂FBV和CBV 是指url 和view的對應關系
FBV function base view /url/ --> 函數 CBV class base view /url/ -->類
上述都是FBV的方式。下面對CBV進行說明:
- urls.py
url(r'^cbv',views.CBVtest.as_view()),
- views.py
class CBVtest(View): def dispatch(self, request, *args, **kwargs): print("類似裝飾器:before") result = super(CBVtest, self).dispatch(request, *args, **kwargs) print("類似裝飾器:after") return result def get(self, request): # 定義get方法,get請求執行這個方法 print(request.method) return HttpResponse('cbvget') def post(self, request): # 定義post方法,post請求執行這個方法 print(request.method) return HttpResponse('cbvpost')
URL反相解析
在我們的Django項目中,我們經常會遇到要在視圖中返回一個重定向到具體URL的響應,或者要將具體的URL地址嵌入到HTML頁面中(如:a標簽的href屬性等)的情況。我們之前通常都會選擇硬編碼(寫死)的方式來實現類似上述的需求,但是這並不是最優的解決辦法。例如:
在視圖函數中
def add_student(request): if request.method == "POST": ... return redirect("/student_list/") # 將URL硬編碼到視圖中 ...
在模板文件的HTML文件中:
<a href="/student_list/">點擊查看所有學生信息</a>
Django框架充分考慮了這種需求,所以提供了工具來反向解析(推導)出具體的URL。
反相解析定義
隨着功能的增加會出現更多的視圖,可能之前配置的正則表達式不夠准確,於是就要修改正則表達式,但是正則表達式一旦修改了,之前所有對應的超鏈接都要修改,真是一件麻煩的事情,而且可能還會漏掉一些超鏈接忘記修改,有辦法讓鏈接根據正則表達式動態生成嗎? 就是用反向解析的辦法
應用范圍
模板中的超鏈接
視圖中的重定向
使用方法
namespace和name屬性
定義url時,需要為include定義namespace屬性,為url定義name屬性
使用時,在模板中使用url標簽,在視圖中使用reverse函數,根據正則表達式動態生成地址,減輕后期維護成本。
模板中超鏈接步驟
1)在項目urls.py中為include定義namespace屬性。
url(r’^’,include(‘booktest.urls’,namespace=’booktest’)),
2)在應用的urls.py中為url定義name屬性,並修改為fan2。
url(r’^fan2/$’, views.fan2,name=’fan2’),
3)在模板中使用url標簽做超鏈接,此處為templates/booktest/fan1.html文件。
<html> <head> <title>反向解析</title> </head> <body> 普通鏈接:<a href="/fan2/">普通fan2</a> <hr> 反向解析:<a href="{%url 'booktest:fan2'%}">反向解析fan2</a> </body> </html>
4)回到瀏覽器中,后退,刷新,查看源文件,兩個鏈接地址一樣。
5)在應用的urls.py中,將fan2修改為fan_show。
url(r’^fan_show/$’, views.fan2,name=’fan2’),
6)回到瀏覽器中,刷新,查看源文件,兩個鏈接地址不一樣。
視圖中的重定向
from django.shortcuts import redirect from django.core.urlresolvers import reverse return redirect(reverse('booktest:fan2'))
反向解析中URL的參數
位置參數
1)在booktest/urls.py中,修改fan2如下:
url(r’^fan(\d+)_(\d+)/$’, views.fan2,name=’fan2’),
2)修改templates/booktest/fan1.html文件如下:
<html> <head> <title>反向解析</title> </head> <body> 普通鏈接:<a href="/fan2_3/">fan2</a> <hr> 反向解析:<a href="{%url 'booktest:fan2' 2 3%}">fan2</a> </body> </html>
3)回到瀏覽器中,刷新,查看源文件如下圖:
- 使用重定向傳遞位置參數格式如下:
return redirect(reverse(‘booktest:fan’, args=(2,3)))
關鍵字參數
1)在booktest/urls.py中,修改fan2如下:
url(r'^fan(?P<id>\d+)_(?P<age>\d+)/$', views.fan2,name='fan2'),
2)修改templates/booktest/fan1.html文件如下:
<html> <head> <title>反向解析</title> </head> <body> 普通鏈接:<a href="/fan100_18/">fan2</a> <hr> 反向解析:<a href="{%url 'booktest:fan2' id=100 age=18%}">fan2</a> </body> </html>
3)回到瀏覽器中,刷新,查看源文件如下圖:
- 使用重定向傳遞關鍵字參數格式如下:
return redirect(reverse(‘booktest:fan2’, kwargs={‘id’:110,’age’:26}))