定義了數據模型之后,如何通過Django來展示數據?
————模板語言和表單(下一節內容)
這個展示數據的邏輯是怎么控制的?
————控制器邏輯和URL分派機制(這是本節的內容)
先用思維導圖理理思路,再去看技術細節

http://m.survivalescaperooms.com/ganiks/
邏輯導圖導出Word結構:
URL、HTTP機制和視圖1 URL1.1 URLconf介紹1.2 用url替換元組1.3 使用多個Patterns對象1.4 用include來包含其他URL文件1.5 函數對象 v.s. 函數名字符串2 HTTP建模:請求、響應和中間件2.1 請求對象2.1.1 GET和POST字典2.1.2 Cookies和sessions2.1.3 其他服務器變量pathmethodencodingFILESMETAuserraw_post_data2.2 響應對象2.3 中間件2.3.1 請求中間件2.3.2 響應中間件3 視圖與邏輯3.1 就是Python函數3.2 通用視圖3.3 半通用視圖3.4 自定義視圖將一個請求的URL和結果的響應聯系起來的機制就是任何Web開發框架的關鍵所在
Django使用的是一種簡單而強大的機制, 讓你可以通過正則表達式配置映射到Python的視圖方法上,并通過互相包含把他們連接在一起
這個“映射”存放路徑一般是這樣mysite/mysite/urls.py
from django.conf.urls import patterns, include, urlurlpatterns = patterns('mysite.myapp.views', (r'^$', 'index'), (r'^archives/(?P<year>/d{4})/(?P<month>/d{2})/(?P<day>/d{2})/$', 'archieve'),)這個文件暴露一個對象urlpatterns,這個對象由函數patterns生成,并包含2點:
mysite.myapp.views.index and mysite.myapp.views.archieve一個或多個元組
注意注意:由于到處都是打頭的斜杠
/,故省略。即r'^$'其實是r'^/$', 定義的就是首頁
這個例子中的正則表達式包含了一個很重要的概念符號組,如(?P<year>/d{4}),用來撲捉部分URL的變化,這是定義動態URL的關鍵。
后面通過
下面通過4個步驟,將這個實例,將Django的URL機制持續優化
上面提到url patterns定義的第二部分是一個或者多個元組,這里將元組優化成一個url方法,這個方法有4個參數,前三個對應了前面提到的三個
根據url方法,重寫下
from django.conf.urls.defaults import *urlpatterns = patterns('mysite.myapp.views', url(r'^$', 'index', name='index'), url(r'^archives/(?P<year>/d{4})/(?P<month>/d{2})/(?P<day>/d{2})/$', 'archieve', name='archives'),)使用url方法的意義在哪里?---原來元組中的第三個參數是個“位置參數”會讓設置變得不那么靈活;而替換之后,第三個第四個參數都是“命名參數”,你可以一個都不指定,指定一個,或者都指定,這樣就更強大和靈活了。
把URL打散到多個patterns調用里,是當URL很多時一個必然的趨勢;而patterns返回的類型正好是一個Django內部對象類型,很方便被當做列表或者其他容器類型一樣附加元素,這樣就可以方便將多個這樣的對象鏈接起來
一般,會按照“前綴字符串”將所有的URL分開,在通過+=符號鏈接起來
from django.conf.urls.defaults import *urlpatterns = patterns('mysite.myapp.views', url(r'^$', 'index'), url(r'^blog/new/$', 'new_post'),)urlpatterns += patterns('mysite.guestbook.views', url(r'^guestbook/$', 'index'), url(r'^guestbook/add/$', 'new_entry'), ...guestbook...)urlpatterns += patterns('mysite.catalog.views', url(r'^catalog/$', 'index'), ...catalog...)貌似還是挺麻煩,是不是還有優化的余地?這里還是重復寫了很多次的
guestbookcatalog
前面一步將patterns拆分成多個patterns調用,其實還可以進一步拆分到多個urls.py文件,并讓一個主URL定義文件通過include來調用其他的子URL定義文件
##urls.py##blog/urls.py##guestbook/urls.py##catalog/urls.py##urls.pyfrom django.conf.urls.defaults import *urlpatterns = patterns('mysite.myapp.blog.views', url(r'^$', 'index'), url(r'^blog/', include('mysite.myapp.blog.urls')),)urlpatterns += patterns('', url(r'^guestbook/', include('mysite.myapp.guestbook.urls')),)urlpatterns += patterns('', url(r'^catalog/', include('mysite.myapp.catalog.urls')),)##blog/urls.pyurlpatterns = patterns('mysite.myapp.blog.views', url(r'^new/$', 'new_post'), url(r'^topics/(?P<topic_name>/w+)/new/$', 'new_post')),)##guestbook/urls.pyurlpatterns = patterns('mysite.myapp.guestbook.views', url(r'^$', 'index'), url(r'^add/$', 'new_entry')),)##catalog/urls.pyurlpatterns = patterns('mysite.myapp.catalog.views', url(r'^$', 'index'),)這樣一來,好處多多:
blog guestbook catalog函數名字符串說的是url()方法的第二個參數, 如'index', 'new_entry'
Django不光允許你用函數名字符串,還允許用“函數對象”
from django.conf.urls.defaults import *from mysite.myapp import viewsurlpatterns = patterns('', url(r'^$', views.index), url(...),)到此為止,URL部分解決的是什么問題? -- 如何設置URL定義以及如何將URL和視圖(視圖函數)聯系起來
下面看看這些視圖函數的周圍都有些什么
Django把HTTP歸結為簡單的Python請求對象+響應對象(這點跟Yii2很像哦)
加上URL轉發和視圖函數,一個請求在你的Web應用程序中的流程如下:
下面說說思路,先看看請求對象和響應對象,以及他們的組件,然后深入Django中間件,這個中間件提供了進入上述過程中多個步驟的接口
所有視圖函數都接受一個“請求”參數HttPRequest對象,這是一組經過良好封裝的屬性,代表了從Web服務器傳遞進來的原始HTTP請求。
其中最常用的屬性是請求數據是GET和POST數據結構。
這個GET和POST數據結構一Python字典的形式出現,即 request.GET request.POST (雖然結構相同,但是填充方法很不一樣)
他們一起為參數化Web請求提供了一個靈活的方式。
例如:請求URL為/userlist/?page=2對應的處理為:
def userlist(request): return paginated_userlist_page(page=request.GET['page'])同理,還有request.POST和request.REQUEST(不常用,因為pythonic哲學建議“盡可能顯式表達意思而不要依賴于默認行為”
請求對象里接下來最常用的是request.COOKIES,也是一個字典,代表了存儲在用戶瀏覽器中的HTTP Cookies
通長,cookies使用支持會話session的
Django里的會話也是HttpRequest對象的一個字典類屬性,注意,這里request.session的session是小寫,因為session并不是HTTP協議的一部分
響應要比請求簡單,其主要數據就是存在content屬性里的正文,一般而言就是一個大大的HTML字符串
response = HttpResponse("<html>this is a tiny web page</html>")response = HttpResponse()response.write("<html>")response.write("this is a tiny web page")response.write("</html>")response["Content-Type"] = "text/csv"response["Content-Length"] = 256看來,Django的基本流程還是簡單的,接受請求-找到合適的視圖函數-返回響應,不過還可以在上面加諸更多層次(中間件)來讓其更靈活強大
中間件 middleware 可以在多個地方改變輸入和輸出
在settings.py文件里的MIDDLEWARE_CLASSES元組中列出后,Django會內省這些類并且在適當的時候調用其方法。
有些類則需要特定的"contrib."應用程序支持,比如認證框架
請求中間件用在輸入端,定義為一個實現了process_request方法的類,
此方法接受request作為參數,返回一個HttpResponse或者子類的對象,或者返回None(Django繼續處理其他請求中間件)
from some_exterior_auth_lib import get_userclass ExteriorAuthMiddleware(object): def process_request(self, request): token = request.COOKIES.get('auth_token') if token is None and not request.path.startswith('/login') return HttpResponseRedirect('/login') request.exterior_user = get_user(token)這個例子中,請求中間件給請求對象添加了額外屬性request.exterior_user,添加了之后,process_request隱含返回None(如果沒有顯式的return語句,python函數一定返回None);然后Django會繼續處理其他請求中間件,最后才輪到視圖函數本身
如果,token無效的話,中間件會把用戶redirect到登陸頁,因為是請求中間件,重定向之后的所有代碼都會忽略掉不執行。
可見,請求中間件有2個特性,給請求對象添加額外屬性+返回一個立刻發送給請求客戶端的HttpResponse(或子類)對象,之后代碼忽略
響應中間件運行在視圖函數返回的HttpResponse對象之上,實現一個process_response方法
此方法接受request和response兩個參數,返回一個HttpResponse或者子類的對象
class TextFilterMiddleware(object): def process_response(self, request, response): response["Content-Type"] = "text/csv" response.content = response.content.replace('foo', 'bar')可見,響應中間件主要作用是在響應里插入額外的頭信息,或者處理響應內容
因為之前我熟悉的是php的Yii框架,那里的視圖概念跟Django這里的完全不是一碼事
這里的視圖也叫控制器!!!是Django的核心,提供了幾乎所有的實際的程序邏輯
在定義和使用models的時候,我們是數據庫管理員
在編寫template的時候,我們是界面設計師
在編寫views視圖的時候,我們才是真正的軟件工程師
簡單說,在Python中,視圖就是函數
唯一要求是:這個函數接受一個HttpRequest對象并返回一個HttpResponse對象,另外在URLconf中的正則模式中定義命名組(named group)和可選的字典參數作為該函數的參數,舉例:
urlpatterns = patterns('mysite.myapp.views', url(r'^archives/(?P<year>/d{4})/(?P<month>/d{2})/(?P<day>/d{2})/$'), 'archive', {'show_private': True},)from django.http import HttpResponsedef archive(request, year, month, day, show_private): return HttpResponse()通用視圖一般都提供了很多選項,有些是某個視圖特有的,但是其它都是全局的,比如:
template_name - 允許用戶重寫視圖模板位置extra_context - 字典,允許用戶向模板context傳遞額外的信息 (具體細節看下一節06節)通用視圖都是組成一個兩層的模塊層次:
使用通用視圖,用戶只需要在URLconf文件里引用它們,傳遞適合的參數,并確保視圖要渲染和返回的模板存在即可:
from django.views.generic.list_detail import object_detailfrom django.confi.urls.defaults import *from mysite.myapp.models import Personurlpatterns = patterns('', url(r'^people/(?P<object_id>/d+)/$', object_detail, { 'queryset' : Person.objects.all() }))這個例子中,定義了一個正則匹配 /people/25/ 這樣的URL
用到的通用視圖 object_detail 需要兩個參數,分別是 object_id 和 一個 QuerySet,分別從URL參數和字典參數提供。
上面例子中 queryset 不光可以是 Person.objects.all(), 也可以是 Person.objects.filter(is_employee=True),
但是,不能是 Person.objects.filter(id=object_id)
這是 URLconf自身固有的限制,你不能在正則表達式解析之前對撲捉到的URL參數進行任何操作,那怎么辦呢?
半通用視圖可以完美解決這個問題,將 對通用視圖和數據模型的部分從urls.py中摘出去放在視圖文件中
## urls.pyfrom django.conf.urls.defaults iimport *urlpatterns = patterns('mysite.myapp.views', url(r'^people/by_lastname/(?P<last_name>/w+)/$', 'last_name_search'),)## view.pyfrom django.views.generic.list_detail import object_listfrom mysite.myapp.models import Person def last_name_search(request, last_name): return object_list(request, queryset = Person.objects.filter(last__istartswith=last_name) }如何?完美解決了這個問題吧
雖然函數接受了一個在URL正則中命名組里定義的last_name參數,但是還是把99%的工作給了通用視圖,之所以可以這樣,就是因為通用視圖就是普通Python函數,一樣可以導入和調用
http://m.survivalescaperooms.com/ganiks/p/django-url-http-mechnism-and-views.html
上面兩種都離不開通用視圖,但有時候就是沒法用通用視圖
一旦自定義視圖,Django基本上就不再對你做任何限制了,但是它還是提供了一些捷徑給你,其中大多數都屬于django.shotcuts模塊
from django.shortcuts import render_to_responsefrom django.http import Http404from mysite.myapp.models import Persondef person_detail(request, id): try: person = Person.objects.get(pk=id) except Person.DoesNotExist: raise Http404 return return_to_response("person/detail.html", {"person":person})第二種寫法會簡捷很多
from django.shotcuts import render_to_response, get_object_or_404from mysite.myapp.models import Persondef person_detail(request, id): person = get_object_or_404(Person, pk=id) return render_to_response("person/detail.html", {"person":person})以后在定義視圖的過程中,你會發現更喜歡用args/kwargs的方式,因為它們可以接受任何位置參數和關鍵字參數,靈活快捷,你不用再回到URLconf中去記住你是怎么捕捉正則參數或是關鍵字參數命名了。
def myview(*args, **kwargs): # ... args[0] # ... kwargs['object_id']http://m.survivalescaperooms.com/ganiks/p/django-url-http-mechnism-and-views.html
本節完,下一節關于模板渲染網頁以及表單和表單驗證。
新聞熱點
疑難解答