django複習-3-請求與響應
一、請求request
前端向後端傳遞引數有幾種方式?
- 提取URL的特定部分,如/weather/beijing/2018,可以在伺服器端的路由中用正則表示式擷取; "http://127.0.0.1/weather/beijing/2018"
- 查詢字串(query string),形如key1=value1&key2=value2; "http://127.0.0.1/weather/?area=beijing&year=2018"
- 請求體(body)中傳送的資料,比如表單資料、json、xml; "POST方法的請求體中"
- 在http報文的頭(header)中。
1.URL路徑傳參
任何一種請求方式都可以通過路徑傳參 POST GET PUT DELETE
命名引數按定義順序傳遞,如
urlpatterns = [ url(r'^weather/([a-z]+)/(\d{4})/$', views.weather) ] def weather(request, city, year): return HttpResponse("您查詢的城市是%s年份是%s" % (city, year))
直接在url路徑裡寫入引數,後端在匹配路由的時候,通過正則的方式提取到引數,在檢視函式中,按照順序來傳入引數
命名引數按名字傳遞,如
urlpatterns = [ url(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather), ] def weather(request, year, city): return HttpResponse("您查詢的城市是%s年份是%s" % (city, year))
命名引數在往檢視函式中傳遞的時候不用在意傳入的順序,但是傳入的引數名字要和正則裡保持一致
2.查詢字串傳參
獲取請求路徑中的查詢字串引數(形如?k1=v1&k2=v2),可以通過request.GET屬性獲取,返回QueryDict物件。
# 請求地址 http://127.0.0.1:8000/qs/?a=aaa&b=bbb&a=a2222 def qs(request): query_dict = request.GET a = query_dict.get('a') b = query_dict.get('b') alist = query_dict.getlist('a') print(a, b, alist) # a2222 bbb ['aaa', 'a2222'] return HttpResponse("OK") # url配置 urlpatterns = [ url(r'^qs/$', views.qs), ]
可以看出,當查詢字串中有多個相同名字的引數時,如果呼叫get方法,獲取的是最後一個的值,getlist方法返回的是一個列表
重要:查詢字串不區分請求方式,即假使客戶端進行POST方式的請求,依然可以通過request.GET獲取請求中的查詢字串資料。
使用postman來進行post請求,需要先在settings配置檔案中關閉CSRF中介軟體
3.請求體傳參
請求體資料格式不固定,可以是表單型別字串,可以是JSON字串,可以是XML字串,應區別對待。
可以傳送請求體資料的請求方式有POST、PUT、PATCH、DELETE。
Django預設開啟了CSRF防護,會對上述請求方式進行CSRF防護驗證,在測試時可以關閉CSRF防護機制,方法為在settings.py檔案中註釋掉CSRF中介軟體
3.1表單型別 Form Data
前端傳送的表單型別的請求體資料,可以通過request.POST屬性獲取,返回QueryDict物件。
重要:request.POST只能用來獲取POST方式的請求體表單資料。
演示
def qs(request): query_dict = request.GET a = query_dict.get('a') b = query_dict.get('b') alist = query_dict.getlist('a') print("查詢字串是分別是%s,%s,%s" % (a, b, alist)) post_dict = request.POST c_post = post_dict.get('c') d_post = post_dict.get('d') c_list = post_dict.getlist('c') print("表單資料是分別是%s,%s,%s" % (c_post, d_post, c_list)) return HttpResponse("OK")
同時可以用request.GET和request.POST
3.2非表單型別
非表單型別的請求體資料,Django無法自動解析,可以通過request.body屬性獲取最原始的請求體資料,自己按照請求體格式(JSON、XML等)進行解析。request.body返回bytes型別。
def json_view(request): json_bytes = request.body req_dict = json.loads(json_bytes.decode()) a = req_dict.get("a") b = req_dict.get("b") return HttpResponse("獲取到a是%s,b是%s" % (a, b))
python3.6版本以後,json.loads()既能接受bytes型別,也能接受str型別,但是3.6之前的版本,只能接受str型別,所以如果是python3.6以前的版本,decode()一下就好
3.3請求頭
可以通過request.META屬性獲取請求頭headers中的資料,request.META為字典型別。
常見的請求頭如:
CONTENT_LENGTH – The length of the request body (as a string). CONTENT_TYPE – The MIME type of the request body. HTTP_ACCEPT – Acceptable content types for the response. HTTP_ACCEPT_ENCODING – Acceptable encodings for the response. HTTP_ACCEPT_LANGUAGE – Acceptable languages for the response. HTTP_HOST – The HTTP Host header sent by the client. HTTP_REFERER – The referring page, if any. HTTP_USER_AGENT – The client’s user-agent string. QUERY_STRING – The query string, as a single (unparsed) string. REMOTE_ADDR – The IP address of the client. REMOTE_HOST – The hostname of the client. REMOTE_USER – The user authenticated by the Web server, if any. REQUEST_METHOD – A string such as "GET" or "POST". SERVER_NAME – The hostname of the server. SERVER_PORT – The port of the server (as a string).
具體使用
def get_headers(request): print(request.META['CONTENT_TYPE']) return HttpResponse('OK')
4.其他常用HttpRequest物件屬性
- method:一個字串,表示請求使用的HTTP方法,常用值包括:'GET'、'POST'。
- user:請求的使用者物件。
- path:一個字串,表示請求的頁面的完整路徑,不包含域名和引數部分。
- encoding:一個字串,表示提交的資料的編碼方式。
- 如果為None則表示使用瀏覽器的預設設定,一般為utf-8。
- 這個屬性是可寫的,可以通過修改它來修改訪問表單資料使用的編碼,接下來對屬性的任何訪問將使用新的encoding值。
- FILES:一個類似於字典的物件,包含所有的上傳檔案。
二、響應
檢視在接收請求並處理後,必須返回HttpResponse物件或子物件。HttpRequest物件由Django建立,HttpResponse物件由開發人員建立。
1.HttpResponse
可以使用django.http.HttpResponse來構造響應物件。
HttpResponse(content=響應體, content_type=響應體資料型別, status=狀態碼)
演示
def response(request): s = '{"name": "zhangsan", "age": 21}' return HttpResponse(s, content_type='application/json', status=200) # url配置 urlpatterns = [ url(r'^resp$', views.response), ]
也可通過HttpResponse物件屬性來設定響應體、狀態碼:
- content:表示返回的內容。
- status_code:返回的HTTP響應狀態碼。
def response(request): resp = HttpResponse() resp.content = "hello world!" resp.status_code = 200 resp["It"] = "hello" return resp
其實就是在例項化物件之後,再設定響應體和狀態碼
設定響應頭的方法就是 resp["It"] = "hello"
HttpResponse子類
Django提供了一系列HttpResponse的子類,可以快速設定狀態碼
- HttpResponseRedirect 301
- HttpResponsePermanentRedirect 302
- HttpResponseNotModified 304
- HttpResponseBadRequest 400
- HttpResponseNotFound 404
- HttpResponseForbidden 403
- HttpResponseNotAllowed 405
- HttpResponseGone 410
- HttpResponseServerError 500
JsonResponse
若要返回json資料,可以使用JsonResponse來構造響應物件,作用:
- 幫助我們將資料轉換為json字串
- 設定響應頭Content-Type為 application/json
from django.http import JsonResponse def demo_view(request): return JsonResponse({'city': 'beijing', 'subject': 'python'})
redirect重定向
from django.shortcuts import redirect def demo_view(request): return redirect('/index.html')
Cookie
Cookie,有時也用其複數形式Cookies,指某些網站為了辨別使用者身份、進行session跟蹤而儲存在使用者本地終端上的資料(通常經過加密)。Cookie最早是網景公司的前僱員Lou Montulli在1993年3月的發明。Cookie是由伺服器端生成,傳送給User-Agent(一般是瀏覽器),瀏覽器會將Cookie的key/value儲存到某個目錄下的文字檔案內,下次請求同一網站時就傳送該Cookie給伺服器(前提是瀏覽器設定為啟用cookie)。Cookie名稱和值可以由伺服器端開發自己定義,這樣伺服器可以知道該使用者是否是合法使用者以及是否需要重新登入等。伺服器可以利用Cookies包含資訊的任意性來篩選並經常性維護這些資訊,以判斷在HTTP傳輸中的狀態。Cookies最典型記住使用者名稱。
Cookie是儲存在瀏覽器中的一段純文字資訊,建議不要儲存敏感資訊如密碼,因為電腦上的瀏覽器可能被其它人使用。
Cookie的特點
- Cookie以鍵值對的格式進行資訊的儲存。
- Cookie基於域名安全,不同域名的Cookie是不能互相訪問的,如訪問qq.com時向瀏覽器中寫了Cookie資訊,使用同一瀏覽器訪問baidu.com時,無法訪問到qq.com寫的Cookie資訊。
- 當瀏覽器請求某網站時,會將瀏覽器儲存的跟網站相關的所有Cookie資訊提交給網站伺服器。
設定Cookie
可以通過HttpResponse物件中的set_cookie方法來設定cookie。
HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)
- max_age 單位為秒,預設為None。如果是臨時cookie,可將max_age設定為None。
示例:
def set_cookie(request): resp = HttpResponse("設定cookie") resp.set_cookie("name","zhangsan") # 這是一個臨時的cookie,退出瀏覽器就沒了 resp.set_cookie("name2", "lisi", max_age=3600) # 有效期一個小時的cookie return resp # url配置 urlpatterns = [ url(r'^cookie/$', views.set_cookie), ]
效果
上面的這個是臨時cookie
上面的這個是有效期一小時的cookie
讀取Cookie
可以通過HttpRequest物件的COOKIES屬性來讀取本次請求攜帶的cookie值。request.COOKIES為字典型別。
def look(request): name2 = request.COOKIES.get("name2") return HttpResponse("name2的值是%s" % name2)
效果
這時候去看還有沒有name這個cookie
發現只有這兩個
Session
啟用Session
Django專案預設啟用Session。
可以在settings.py檔案中檢視,如圖所示
session是什麼意思
cookie是存在前端的,session是存在後端的,那麼session是存在哪呢
session可以存放在資料庫中、本地快取(程式的執行記憶體中,全域性變數)、檔案裡、redis裡
Django的session儲存方式
在settings.py檔案中,可以設定session資料的儲存方式,可以儲存在資料庫、本地快取等。
資料庫
儲存在資料庫中,如下設定可以寫,也可以不寫,這是預設儲存方式。
SESSION_ENGINE='django.contrib.sessions.backends.db'
如果儲存在資料庫中,需要在項INSTALLED_APPS中安裝Session應用。
資料庫中的表如圖所示
表結構是
由表結構可知,操作Session包括三個資料:鍵,值,過期時間。
本地快取
儲存在本機記憶體中,如果丟失則不能找回,比資料庫的方式讀寫更快。
SESSION_ENGINE='django.contrib.sessions.backends.cache'
儲存在本機記憶體中的話,如果程式重新啟動,那麼之前的session就都沒了
混合儲存
優先從本機記憶體中存取,如果沒有則從資料庫中存取。
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
本地快取跨機問題
伺服器肯定不只是一個伺服器,如果使用本地儲存來存放session的話,使用者在第一臺伺服器登陸,然後session儲存在第一臺伺服器了,如果第二次訪問的時候,nginx把使用者分到了第二臺伺服器上,那麼第二臺伺服器上沒有儲存使用者的session,會造成使用者還需要登陸,所以為了解決這個問題,就需要使用redis來儲存session
使用django-redis儲存session
在redis中儲存session,需要引入第三方擴充套件,我們可以使用django-redis來解決。
安裝擴充套件
pip install django-redis
在settings.py檔案中做如下設定
CACHES = { "default": { "BACKEND": "django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379/1", "OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient", } } } SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default"
上面的配置資訊放在settings檔案的最後
設定session
def session(request): request.session['name'] = "zhangsan" request.session['age'] = 21 return HttpResponse("設定session成功") # url配置 urlpatterns = [ url(r'^session$', views.session), ]
發現有資料,這個key是django-redis自動生成的。
Session操作
通過HttpRequest物件的session屬性進行會話的讀寫操作。
1) 以鍵值對的格式寫session。
request.session['鍵']=值
2)根據鍵讀取值。
request.session.get('鍵',預設值)
3)清除所有session,在儲存中刪除值部分。
request.session.clear()
4)清除session資料,在儲存中刪除session的整條資料。
request.session.flush()
5)刪除session中的指定鍵及值,在儲存中只刪除某個鍵及對應的值。
del request.session['鍵']
6)設定session的有效期
request.session.set_expiry(value)
- 如果value是一個整數,session將在value秒沒有活動後過期。
- 如果value為0,那麼使用者session的Cookie將在使用者的瀏覽器關閉時過期。
- 如果value為None,那麼session有效期將採用系統預設值,預設為兩週,可以通過在settings.py中設定SESSION_COOKIE_AGE來設定全域性預設值。