標籤:
Django使用request和response對象在系統間傳遞狀態。—(阿倫)
當一個頁面被請示時,Django建立一個包含請求中繼資料的 HttpRequest 對象。 然後Django調入合適的視圖,把
HttpRequest 作為視圖的函數的第一個參數 傳入。每個視圖要負責返回一個 HttpResponse 對象。
HttpRequest對象
HttpRequest 表示來自某用戶端的一個單獨的HTTP請求。
HttpRequest執行個體的屬性包含了關於此次請求的大多數重要訊息(詳見表H-1)。 除了session外的所有屬性都應該認為是唯讀.
表 H-1. HttpRequest對象的屬性
屬性 描述
path 表示提交請求頁面完整地址的字串, 不包括網域名稱,如 "/music/bands/the_beatles/" 。
method 表示提交請求使用的HTTP方法。 它總是大寫的。例如:
if request.method == ‘GET‘:
do_something()
elif request.method == ‘POST‘:
do_something_else()
GET 一個類字典對象,包含所有的HTTP的GET參數的資訊。 見 QueryDict 文檔。
POST 一個類字典對象,包含所有的HTTP的POST參數的資訊。 見 QueryDict 文檔。
通過POST提交的請求有可能包含一個空的 POST 字典, 也就是說, 一個通過POST方法提交的表
單可能不包含資料。 因此,不應該使用 if request.POST 來判斷POST方法的使用, 而是使用
if request.method == "POST" (見表中的 method 條目)。
注意: POST 並 不 包含檔案上傳資訊。 見 FILES 。
REQUEST
為了方便而建立,這是一個類字典對象,先搜尋 POST , 再搜尋 GET 。 靈感來自於PHP的
$_REQEUST 。
例如, 若 GET = {"name": "john"} , POST = {"age": ‘34‘} , REQUEST["name"] 會
是 "john" , REQUEST["age"] 會是 "34" 。
強烈建議使用 GET 和 POST ,而不是 REQUEST 。 這是為了向前相容和更清楚的表示。
COOKIES
一個標準的Python字典,包含所有cookie。 鍵和值都是字串。cookie使用的更多資訊見
第12章。
http://djangobook.py3k.cn/appendixH/[2008-10-14 8:28:38]附錄H HTTP請求(Request)和回應(Response)對象
FILES
一個類字典對象,包含所有上傳的檔案。 FILES 的鍵來自 <input type="file" name="" />
中的 name 。 FILES 的值是一個標準的Python字典, 包含以下三個鍵:
filename :字串,表示上傳檔案的檔案名稱。
content-type :上傳檔案的內容類型。
content :上傳檔案的原始內容。
注意 FILES 只在請求的方法是 POST ,並且提交的 <form> 包含
enctype="multipart/form-data" 時 才包含資料。否則, FILES 只是一個空的類字典對
象。
META
一個標準的Python字典,包含所有有效HTTP頭資訊。 有效頭資訊與用戶端和伺服器有關。 這
裡有幾個例子:
CONTENT_LENGTH
CONTENT_TYPE
QUERY_STRING :未解析的原始請求字串。
REMOTE_ADDR :用戶端IP地址。
REMOTE_HOST :用戶端主機名稱。
SERVER_NAME :伺服器主機名稱。
SERVER_PORT :伺服器連接埠號碼。
在 META 中有效任一HTTP頭資訊都是帶有 HTTP_ 首碼的 鍵,例如:
HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE
HTTP_HOST :用戶端發送的 Host 頭資訊。
HTTP_REFERER :被指向的頁面,如果存在的。
HTTP_USER_AGENT :用戶端的user-agent字串。
HTTP_X_BENDER : X-Bender 頭資訊的值, 如果已設的話。
user
一個 django.contrib.auth.models.User 對象表示 當前登入使用者。 若目前使用者尚未登入,
user 會設為 django.contrib.auth.models.AnonymousUser 的一個執行個體。 可以將它們與
is_authenticated() 區別開:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 僅當Django啟用 AuthenticationMiddleware 時有效。
關於認證和使用者的完整細節,見第12章。
session
一個可讀寫的類字典對象,表示當前session。 僅當Django已啟用session支援時有效。 見
第12章。
raw_post_data
POST的未經處理資料。 用於對資料的複雜處理。
Request對象同樣包含了一些有用的方法,見表H-2。
表 H-2. HttpRequest 的方法
http://djangobook.py3k.cn/appendixH/[2008-10-14 8:28:38]附錄H HTTP請求(Request)和回應(Response)對象
方法
__getitem__(key)
描述
請求所給鍵的GET/POST值,先尋找POST,然後是GET。 若鍵不存在,則引發異常
KeyError 。
該方法使使用者可以以訪問字典的方式來訪問一個 HttpRequest 執行個體。
例如, request["foo"] 和先檢查 request.POST["foo"] 再檢查
request.GET["foo"] 一 樣。
has_key() 返回 True 或 False , 標識 request.GET 或 request.POST 是否包含所給的 鍵。
get_full_path() 返回 path ,若請求字串有效,則附加於其後。 例如,
"/music/bands/the_beatles/?print=true" 。
is_secure()
如果請求是安全的,則返回 True 。 也就是說,請求是以HTTPS的形式提交的。
QueryDict 對象
在一個 HttpRequest 對象中, GET 和 POST 屬性都是 django.http.QueryDict 的執行個體。 QueryDict 是一個類似於字典
的類,專門用來處理用一個鍵的多值。當處理一些HTML表單中的元素,特別是 <select multiple="multiple"> 之類傳遞
同一key的多值的元素時,就需要這個類了。
QueryDict 執行個體是不可變的,除非建立了一個 copy() 副本。也就是說不能直接更改 request.POST 和 request.GET 的屬
性。
QueryDict 實現了所有標準的字典的方法,因為它正是字典的一個子類。與其不同的東西都已在表H-3中列出。
表 H-3. QueryDicts 與標準字典的區別
方法 與標準字典實現的不同
__getitem__ 與一個字典一樣。但是,當一個鍵有多個值時, __getitem__() 返回最後一個值。
__setitem__ 將所給鍵的值設為 [value] (一個只有一個 value 元素的 Python列表)。 注意,因對其它的字典
函數有副作用,故它只能被稱 為一個可變的 QueryDict (通過 copy() 建立)。
get() 如果一個鍵多個值,和 __getitem__ 一樣, get() 返回 最後一個值。
update() 參數是一個 QueryDict 或標準字典。 和標準字典的
update 不同,這個方法*增加*而不是替換一項內容:
>>> q = QueryDict(‘a=1‘)
>>> q = q.copy() # 使其可變
>>> q.update({‘a‘: ‘2‘})
>>> q.getlist(‘a‘)
[‘1‘, ‘2‘]
>>> q[‘a‘] # 返回最後一個值
[‘2‘]
items()
和標準字典的 items() 方法一樣, 不同的是它和 __getitem()__ 一樣,返回最後一個值:
>>> q = QueryDict(‘a=1&a=2&a=3‘)
>>> q.items()
http://djangobook.py3k.cn/appendixH/[2008-10-14 8:28:38]附錄H HTTP請求(Request)和回應(Response)對象
[(‘a‘, ‘3‘)]
values()
和標準字典的 values() 方法一樣, 不同的是它和 __getitem()__ 一樣,返回最後一個值。
另外, QueryDict 還有在表H-4中列出的方法。
表 H-4. 附加的 (非字典的) QueryDict 方法
方法 描述
copy() 返回一個對象的副本,使用的是Python標準庫中的 copy.deepcopy() 。 該副本是可變
的, 也就是說,你能改變它的值。
getlist(key)
以Python列表的形式返回所請求鍵的資料。 若鍵不存在則返回空列表。 它保證了一定會返
回某種形式的list。
setlist(key, list_) 將所給鍵的索引值設為 list_ (與 __setitem__() 不同)。
appendlist(key, item) 在 key 相關的list上增加 item 。
setlistdefault(key, l) 和 setdefault 一樣, 不同的是它的第二個參數是 一個列表,而不是一個值。
lists() 和 items() 一樣, 不同的是它以一個列表的形式 返回字典每一個成員的所有值。 例如:
>>> q = QueryDict(‘a=1&a=2&a=3‘)
>>> q.lists()
[(‘a‘, [‘1‘, ‘2‘, ‘3‘])]
urlencode()
返回一個請求字串格式的資料字串 (如, "a=2&b=3&b=5" )。
一個完整的例子
例如, 給定這個HTML表單:
<form action="/foo/bar/" method="post">
<input type="text" name="your_name" />
<select multiple="multiple" name="bands">
<option value="beatles">The Beatles</option>
<option value="who">The Who</option>
<option value="zombies">The Zombies</option>
</select>
<input type="submit" />
</form>
如果使用者在 your_name 中輸入 "John Smith" ,並且在多選框中同時選擇了The Beatles和The Zombies,那麼以下就
是Django的request對象所擁有的:
>>> request.GET
{}
>>> request.POST
{‘your_name‘: [‘John Smith‘], ‘bands‘: [‘beatles‘, ‘zombies‘]}
>>> request.POST[‘your_name‘]
‘John Smith‘
http://djangobook.py3k.cn/appendixH/[2008-10-14 8:28:38]附錄H HTTP請求(Request)和回應(Response)對象
>>> request.POST[‘bands‘]
‘zombies‘
>>> request.POST.getlist(‘bands‘)
[‘beatles‘, ‘zombies‘]
>>> request.POST.get(‘your_name‘, ‘Adrian‘)
‘John Smith‘
>>> request.POST.get(‘nonexistent_field‘, ‘Nowhere Man‘)
‘Nowhere Man‘
使用時請注意:
GET , POST , COOKIES , FILES , META , REQUEST , raw_post_data 和 user 這些屬性都是消極式載入的。 也就是說除非代
碼中訪問它們,否則Django並不會花費資源來計算這些屬性值。
HttpResponse
與Django自動建立的 HttpRequest 對象相比, HttpResponse 對象則是由你建立的。 你建立的每個視圖都需要執行個體化,處
理和返回一個 HttpResponse 對象。
HttpResponse 類存在於 django.http.HttpResponse 。
構造HttpResponse
一般情況下,你建立一個 HttpResponse 時,以字串的形式來傳遞頁面的內容給 HttpResponse 的建構函式:
>>> response = HttpResponse("Here‘s the text of the Web page.")
>>> response = HttpResponse("Text only, please.", mimetype="text/plain")
但是如果希望逐漸增加內容,則可以把 response 當作一個類檔案對象使用:
>>> response = HttpResponse()
>>> response.write("<p>Here‘s the text of the Web page.</p>")
>>> response.write("<p>Here‘s another paragraph.</p>")
你可以將一個迭代器傳遞給 HttpResponse ,而不是固定的字串。如果你要這樣做的話,請遵循以下規則:
迭代器應返回字串。
若一個 HttpResponse 已經通過執行個體化,並以一個迭代器作為其內容,就不能以一個類檔案對象使用 HttpResponse 實
例。這樣做的話,會導致一個 Exception 。
最後,注意 HttpResponse 實現了一個 write() 方法,使其可以在任何可以使用類檔案對象的地方使用。 這方面的例子見
第11章。
設定 Headers
您可以使用字典一樣地添加和刪除頭資訊。
http://djangobook.py3k.cn/appendixH/[2008-10-14 8:28:38]附錄H HTTP請求(Request)和回應(Response)對象
>>> response = HttpResponse()
>>> response[‘X-DJANGO‘] = "It‘s the best."
>>> del response[‘X-PHP‘]
>>> response[‘X-DJANGO‘]
"It‘s the best."
你也可以使用 has_header(header) 來檢查一個頭資訊項是否存在。
請避免手工設定 Cookie 頭,參見第12章Django中cookie工作原理的說明。
HttpResponse的子類
Django包含許多處理不同類型的HTTP請求的 HttpResponse 子類(見表H-5)。像 HttpResponse 一樣,這些類在
django.http 中。
表 H-5. HttpResponse 子類
類名
HttpResponseRedirect
描述
建構函式的參數有一個: 重新導向的路徑。 它可以是一個完整的URL (例
如, ‘http://search.yahoo.com/‘ ) 或者不包括網域名稱的絕對路徑
(如 ‘/search/‘ )。 注意它返回 HTTP 狀態代碼 302。
HttpResponsePermanentRedirect
類似 HttpResponseRedirect , 但是它 返回一個永久轉義 (HTTP
狀態代碼 301), 而不是暫時性轉移(狀態代碼302)。
HttpResponseNotModified 建構函式沒有任何參數。 用它來表示這個頁面在上次請求後未改變。
HttpResponseBadRequest 類似 HttpResponse ,但使用400狀態代碼。
HttpResponseNotFound 類似 HttpResponse ,但使用404狀態代碼。
HttpResponseForbidden 類似 HttpResponse ,但使用403狀態代碼。
HttpResponseNotAllowed 類似 HttpResponse ,但使用405狀態代碼。 它必須有一個參數: 允許
方法的列表。 (例如, [‘GET‘, ‘POST‘] )。
HttpResponseGone 類似 HttpResponse ,但使用410狀態代碼。
HttpResponseServerError 類似 HttpResponse ,但使用500狀態代碼。
當然,如果架構不支援一些特性,你也可以定義自己的 HttpResponse 子類來處理不同的請求。
返回錯誤
在Django中返回HTTP錯誤碼很容易。我們前面已經提到 HttpResponseNotFound , HttpResponseForbidden ,
HttpResponseServerError ,和其它子類。為了更好地表示一個錯誤,只要返回這些子類之一的一個執行個體,而不是一個通常
的 HttpResponse ,例如:
def my_view(request):
# ...
if foo:
return HttpResponseNotFound(‘<h1>Page not found</h1>‘)
http://djangobook.py3k.cn/appendixH/[2008-10-14 8:28:38]附錄H HTTP請求(Request)和回應(Response)對象
else:
return HttpResponse(‘<h1>Page was found</h1>‘)
至今為止,404錯誤是最常見的HTTP錯誤,有一種更容易的方式來處理。
當返回一個錯誤,比如 HttpResponseNotFound 時,需要定義錯誤頁面的HTML:
return HttpResponseNotFound(‘<h1>Page not found</h1>‘)
為了方便,而且定義一個通用的應用於網站的404錯誤頁面也是一個很好的選擇,Django提供了一個 Http404 異常。如果在視
圖的任何地方引發 Http404 異常,Django就會捕獲錯誤並返回應用程式的標準錯誤頁面,當然,還有HTTP錯誤碼404。
例如:
from django.http import Http404
def detail(request, poll_id):
try:
p = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
raise Http404
return render_to_response(‘polls/detail.html‘, {‘poll‘: p})
為了完全發揮出 Http404 的功能,應建立一個模板,在404錯誤被引發時顯示。模板的名字應該是 404.html ,而且應該位於
模板樹的最高層。
自訂 404 (無法找到) 視圖
當引發 Http404 異常,Django載入一個專門處理404錯誤的視圖。預設情況下,這個視圖是
django.views.defaults.page_not_found ,它會載入並顯示模板 404.html 。
這意味著需要在根模板目錄定義一個 404.html 模板。這個模板會作用於所有404錯誤。
視圖 page_not_found 適用於99%的網站應用程式程式,但若是希望重載該視圖,可以在URLconf中指定 handler404 ,就像這
樣:
from django.conf.urls.defaults import *
urlpatterns = patterns(‘‘,
...
)
handler404 = ‘mysite.views.my_custom_404_view‘
後台執行時,Django以 handler404 來確定404視圖。預設情況下,URLconf包含以下內容:
from django.conf.urls.defaults import *
這句話負責當前模組中的 handler404 設定。正如你所見,在 django/conf/urls/defaults.py 中, handler404 預設
被設為 ‘django.views.defaults.page_not_found‘ 。
關於404視圖,有三點需要注意:
http://djangobook.py3k.cn/appendixH/[2008-10-14 8:28:38]附錄H HTTP請求(Request)和回應(Response)對象
當Django在URLconf無法找到匹配的Regex時,404視圖會顯示。
如果沒有定義自己的404視圖,而只是簡單地使用預設的視圖,此時就需要在模板目錄的根目錄建立一個 404.html 模
板。預設的404視圖會對所有404錯誤使用改模板。
若 DEBUG 被設為 True (在settings模組內),則404視圖不會被使用,此時顯示的是跟蹤資訊。
自訂 500 (伺服器錯誤) 視圖
同樣地,若是在試圖代碼中出現了執行階段錯誤,Django會進行特殊情況處理。如果視圖引發了一個異常,Django會預設訪問視
圖 django.views.defaults.server_error ,載入並顯示模板 500.html 。
這意味著需要在根模板目錄定義一個 500.html 模板。該模板作用於所有伺服器錯誤。
視圖 server_error 適用於99%的網站應用程式程式,但若是希望重載該視圖,可以在URLconf中指定 handler500 ,就像這
樣:
from django.conf.urls.defaults import *
urlpatterns = patterns(‘‘,
...
)
handler500 = ‘mysite.views.my_custom_error_view‘
django HTTP請求(Request)和回應(Response)對象