Django

利用HTTP協(xié)議向服務(wù)器傳參的幾種途徑勤讽、響應(yīng)厢漩、Cookie膜眠、Session、類視圖溜嗜、中間件

注意:

? 1>Django中的QueryDict對象

? ? ? django 中有一個 QueryDict 對象宵膨,這個對象一般用來存儲瀏覽器傳遞過來的參數(shù),我們可以默認(rèn)把他看成是一個字典

? ? ? 但是它和一般的字典的不同之處在于:

? ? ? ? ? ■ QueryDict 這個字典可以用來處理一個鍵帶有多個值得情況炸宵,即: 一鍵 ===> 多值

? ? ? QueryDict 這個字典支持 get( ) 方法的使用:

? ? ? ? ? ■ 這個位置需要區(qū)分是一鍵一值還是一鍵多值的不同情況:

? ? ? ? ? ? ? 如果是一鍵一值:

QueryDict.get( key ) 獲取的就是當(dāng)前對應(yīng)的值(value)

? ? ? ? ? ? ? 如果是一鍵多值:

QueryDict.get( key ) 獲取的就是最后一個值

? ? ? ? ? ? ? QueryDict 還有一個所有值得方法:

QueryDict.getlist( key ) 獲取這個鍵對應(yīng)的所有值.

? 例如:

? ? ? get( ):

根據(jù)鍵獲取值

如果一個鍵同時擁有多個值將獲取最后一個值

如果鍵不存在則返回None值辟躏,可以設(shè)置默認(rèn)值進行后續(xù)處理

# 默認(rèn)值一般是default,可以省略

QueryDict.get('鍵',默認(rèn)值)

# 或可寫為:

QueryDict['鍵']

? ? ? getlist( ):

根據(jù)鍵獲取值,值以列表返回土全,可以獲取指定鍵的所有值

如果鍵不存在則返回空列表[]捎琐,可以設(shè)置默認(rèn)值進行后續(xù)處理

dict.getlist('鍵',默認(rèn)值)

? 2>Django中CSRF保護的開關(guān)

? ? ? Django默認(rèn)開啟了CSRF防護,會對POST裹匙、PUT瑞凑、PATCH、DELETE請求方式進行CSRF防護驗證

? ? ? 在使用postman測試時可以關(guān)閉CSRF防護機制

? ? ? 關(guān)閉CSRF防護方法為在settings.py文件中注釋掉CSRF中間件概页,如:

? 3>Django中的request.GET和request.POST

? ? ? 查詢字符串不區(qū)分請求方式籽御,即假使客戶端進行POST方式的請求,依然可以通過request.GET獲取請求中的查詢字符串?dāng)?shù)據(jù)惰匙。

? ? ? request.GET 指的不是發(fā)送ajax用的get方法, 而是指從url的查詢字符串中獲取參數(shù)

? ? ? request.POST 指的也不是ajax用的post方法,而是我們從請求體中獲取的參數(shù)

? ? ? 通過上面大家就能明白: GET 和 POST 這里指的都是獲取參數(shù)的位置, 而不是我們以前說的get請求和post請求

? ? ? 如果是從url中(通過查詢字符串)傳遞參數(shù)技掏,使用GET(代表的是傳遞參數(shù)的位置),和請求方法無關(guān)

? ? ? 如果是從請求體中傳遞參數(shù)使用POST

? 4>postman請求體傳遞參數(shù)的4個選項

? ? ? form-data多元素表單

? ? ? x-www-form-urlencoded 正常表單

? ? ? raw (非表單)可以選擇傳輸數(shù)據(jù)的數(shù)據(jù)類型

? ? ? binary二進制

1.利用HTTP協(xié)議向服務(wù)器傳參的幾種途徑

<1>flask框架

? 1>通過URL的特定部分傳參

? ? ? 提取URL的特定部分项鬼,如/weather/2018哑梳,可以在服務(wù)器端的路由中用正則轉(zhuǎn)換器截取

# flask后端接收數(shù)據(jù):

? # 使用正則轉(zhuǎn)換器

? # /user/weather/2018

? @app.route('/user/weather/<re: userid>')

? def index(userid):

print(userid) # 2018

? ? ? return '%s' % userid

? 2>通過查詢字符串(query string)傳遞參數(shù),url中?后形如key1=value1&key2=value2

? ? ? 獲取參數(shù)的方式

request.args.get('key1')

? 3>請求體(body)中發(fā)送的數(shù)據(jù)绘盟,比如表單數(shù)據(jù)鸠真、json悯仙、xml

? ? ? 獲取參數(shù)的方式

request.json.get('key')

? 4>通過http請求報文的請求頭(header)傳遞參數(shù)。

? ? ? 獲取參數(shù)的方式

request.headers.get('content-type')

<2>Django

? 1>通過URL的特定部分傳遞參數(shù)

? ? ? 獲取參數(shù)的方式:視圖函數(shù)傳參

? ? ? ? ? ■ 在定義路由URL時弧哎,可以使用正則表達式提取參數(shù)的方法從URL中獲取請求參數(shù)雁比,Django會將提取的參數(shù)直接傳遞到視圖的傳入?yún)?shù)中。

? ? ? ? ? ■ 未命名參數(shù)按定義順序傳遞(相當(dāng)于位置參數(shù))撤嫩, 如

? url(r'^weather/([a-z]+)/(\d{4})/$', views.weather),

? def weather(request, city, year):

? ? ? print('city=%s' % city) # beijing

? ? ? print('year=%s' % year) # 2008

? ? ? return HttpResponse('OK')

? 命名參數(shù)按名字傳遞(相當(dāng)于關(guān)鍵字參數(shù))偎捎,如

? url(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather),

? def weather(request, year, city):

? ? ? print('city=%s' % city)

? ? ? print('year=%s' % year)

? ? ? return HttpResponse('OK')

? 2>通過請求路徑url中的查詢字符串傳遞參數(shù)(形如?k1=v1&k2=v2)

? ? ? 獲取參數(shù)的方式:request.GET.get('key')

? ? ? ? ? ■ 可以通過request.GET屬性獲取,這個方法返回QueryDict對象序攘。

? ? ? ? ? ■ QueryDict對象類似于一個字典, 所以我們可以通過get() 來獲取 key 值所對應(yīng)的 value 值

a = request.GET.get('a')

? ? b = request.GET.get('b')

? ? alist = request.GET.getlist('a')

? 3>通過請求體傳遞參數(shù)

? ? ? 請求體數(shù)據(jù)格式不固定茴她,可以是表單類型字符串,可以是JSON字符串程奠,可以是XML字符串丈牢,應(yīng)區(qū)別對待。

? ? ? 可以發(fā)送請求體數(shù)據(jù)的請求方式有 POST瞄沙、PUT己沛、PATCH、DELETE距境。

? ? ? 請求體—表單類型 (Form Data)

? ? ? ? ? ■ 獲取參數(shù)的方式:request.POST.get('key')

? ? ? ? ? ■ 前端發(fā)送的表單類型的請求體數(shù)據(jù)申尼,可以通過request.POST屬性獲取,返回QueryDict對象垫桂。

? ? ? ? ? ■ QueryDict對象類似于一個字典, 所以我們可以通過get() 來獲取 key 值所對應(yīng)的 value 值

a = request.POST.get('a')

b = request.POST.get('b')

alist = request.POST.getlist('a')

? 注意:

? ? ? 如果是表單數(shù)據(jù), 發(fā)送的請求不但要求body中是表單的鍵值對

? ? ? 也要求請求頭中content-type的類型是application/x-www-form-urlencoded

? ? ? 如果請求中的不是這樣寫的類型, 上面的request.POST.get( )方法也不可以使用.

? ? ? 如圖所示: (這兩部分都有才可以使用上面的request.POST.get( )方法進行請求)

? ? ? 請求體——非表單類型 (Non-Form Data)

? ? ? ? ? ■ 非表單類型的請求體數(shù)據(jù)师幕,Django無法自動解析

? ? ? ? ? ■ 可以通過request.body屬性獲取最原始的請求體數(shù)據(jù),自己按照請求體格式(JSON诬滩、XML等)進行解析霹粥。

? ? ? ? ? ■ 其中: request.body返回bytes類型。

? ? json_bytes = request.body

? ? json_str = json_bytes.decode()

? ? #python3.6及以上版本中, json.loads()方法可以接收str和bytes類型

? ? #但是python3.5以及以下版本中, json.loads()方法只能接收str,

? ? #所以我們的版本如果是3.5以及以下 需要將bytes類型解碼為str類型

? ? req_data = json.loads(json_str)

? ? print(req_data['a'])

? ? print(req_data['b'])

? 4>通過請求頭傳遞參數(shù)

? ? ? 我們可以通過request.META屬性獲取請求頭headers中的數(shù)據(jù)

? ? ? request.META為字典類型疼鸟。

? ? ? 注意請求頭的用法區(qū)別后控,key的表現(xiàn)形式不同

? ? ? ? ? ■ 我們通過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).

request.META['CONTENT_TYPE']

<3>其他常用的HttpRequest對象屬性

? 1>method:一個字符串,表示請求使用的HTTP方法空镜,常用值包括:'GET'忆蚀、'POST'。

? 2>user:請求的用戶對象姑裂。

? 3>path:一個字符串,表示請求的頁面的完整路徑男旗,不包含域名和參數(shù)部分舶斧。

? 4>encoding:一個字符串,表示提交的數(shù)據(jù)的編碼方式察皇。

? ? ? 如果為None則表示使用瀏覽器的默認(rèn)設(shè)置茴厉,一般為utf-8泽台。

? ? ? 這個屬性是可寫的,可以通過修改它來修改訪問表單數(shù)據(jù)使用的編碼矾缓,接下來對屬性的任何訪問將使用新的encoding值怀酷。

? 5>FILES:一個類似于字典的對象,包含所有的上傳文件嗜闻。

2.響應(yīng)

? 視圖在接收請求并處理后蜕依,必須返回HttpResponse對象或子對象。

? HttpRequest對象由Django創(chuàng)建琉雳,HttpResponse對象由開發(fā)人員創(chuàng)建样眠。

<1>HttpResponse類

? 1>HttpResponse的使用方式

? ? ? 可以從 django.http里面導(dǎo)入HttpResponse

? ? ? from django.http import HttpResponse

HttpResponse(

? ? content=響應(yīng)體,

? ? content_type=響應(yīng)體數(shù)據(jù)類型,

? ? status=狀態(tài)碼

)

? ? ? 通過上式我們知道HttpResponse里面有對應(yīng)的一些參數(shù)可以修改:

? ? ? ? ? ■ content:表示返回的內(nèi)容。

? ? ? ? ? ■ status_code:返回的HTTP響應(yīng)狀態(tài)碼翠肘。

? ? ? ? ? ■ content_type:指定返回數(shù)據(jù)的的MIME類型檐束。

? ? ? 例如:

# 定義一個新的視圖函數(shù)

def demo_response(request):

? ? # 定義一個json字符串

? ? s = '{"name": "python"}'

? ? # 返回一個HttpResponse響應(yīng)對象

? ? return HttpResponse(s, content-type="application/json", status=400)

? 2>HttpResponse特別的使用方式:

? ? ? 我們?nèi)绻枰陧憫?yīng)頭添加自定義的鍵值對內(nèi)容,可以把HttpResponse對象當(dāng)做字典進行響應(yīng)頭鍵值對的設(shè)置:

response = HttpResponse()

# 自定義響應(yīng)頭Itcast, 值為Python

response['Itcast'] = 'Python'

示例:

from django.http import HttpResponse

def demo_view(request):

? ? return HttpResponse('itcast python', status=400)

? ? 或者

? ? response = HttpResponse('itcast python')

? ? response.status_code = 400

? ? response['Itcast'] = 'Python'

? ? return response

<2>HttpResponse子類

? Django提供了一系列HttpResponse的子類束倍,可以快速設(shè)置狀態(tài)碼

? 這個狀態(tài)碼可以從 Django.http 里面導(dǎo)入,例如:

? from django.http import HttpResponseNotFound

? ? ? HttpResponseRedirect 301

? ? ? HttpResponsePermanentRedirect 302

? ? ? HttpResponseNotModified 304

? ? ? HttpResponseBadRequest 400

? ? ? HttpResponseNotFound 404

? ? ? HttpResponseForbidden 403

? ? ? HttpResponseNotAllowed 405

? ? ? HttpResponseGone 410

? ? ? HttpResponseServerError 500

? 使用的演示:

<3>JsonResponse

? 如果我們要返回json字符串, 那么我們可以使用 JsonResponse 來幫助我們快速的構(gòu)建json字符串,進行返回.

? JsonResponse 能夠幫助我們自動把字典轉(zhuǎn)成json字符串類型, 并且還不用自己設(shè)置響應(yīng)頭中contentType字段

? 1>JsonResponse的作用

? ? ? 幫助我們將數(shù)據(jù)轉(zhuǎn)換為json字符串

? ? ? 設(shè)置響應(yīng)頭Content-Type為 application/json

? 2>JsonResponse的使用

# 導(dǎo)入JsonResponse

from django.http import JsonResponse

def demo_view(request):

? ? # 直接返回JsonResponse這個對象,并且里面可以直接傳入?yún)?shù)

? ? return JsonResponse({'city': 'beijing', 'subject': 'python'})

<4>redirect重定向

? 建議redirect(重定向)和我們前面學(xué)習(xí)的reverse(反解析)搭配使用.

? ? ? return redirect(reverse('reqrespspace:getresponse_name'))

? ? ? ? ? ■ reverse('spacename:name')

? 盡量不要把路由寫死. 有利于我們更改開發(fā)代碼.

from django.shortcuts import redirect

def demo_view(request):

? ? return redirect('/index.html')

3.Cookie

? Cookie是存儲在瀏覽器中的一段純文本信息被丧,建議不要存儲敏感信息如密碼,因為電腦上的瀏覽器可能被其它人使用绪妹。

? Cookie甥桂,有時也用其復(fù)數(shù)形式Cookies,指某些網(wǎng)站為了辨別用戶身份喂急、進行session跟蹤而儲存在用戶本地終端上的數(shù)據(jù)(通常經(jīng)過加密)格嘁。

? Cookie最早是網(wǎng)景公司的前雇員Lou Montulli在1993年3月的發(fā)明。

? Cookie是由服務(wù)器端生成廊移,發(fā)送給User-Agent(一般是瀏覽器)糕簿,瀏覽器會將Cookie的key/value保存到某個目錄下的文本文件內(nèi),下次請求同一網(wǎng)站時就發(fā)送該Cookie給服務(wù)器(前提是瀏覽器設(shè)置為啟用cookie)狡孔。

? Cookie名稱和值可以由服務(wù)器端開發(fā)自己定義懂诗,這樣服務(wù)器可以知道該用戶是否是合法用戶以及是否需要重新登錄等。服務(wù)器可以利用Cookies包含信息的任意性來篩選并經(jīng)常性維護這些信息苗膝,以判斷在HTTP傳輸中的狀態(tài)殃恒。

? Cookies最典型記住用戶名。

<1>Cookie的特點

? Cookie以鍵值對的格式進行信息的存儲辱揭。

? Cookie基于域名安全离唐,不同域名的Cookie是不能互相訪問的

? ? ? 如訪問taobao.com時向瀏覽器中寫了Cookie信息,使用同一瀏覽器訪問baidu.com時问窃,無法訪問到taobao.com寫的Cookie信息亥鬓。

? 當(dāng)瀏覽器請求某網(wǎng)站時,會將瀏覽器存儲的跟網(wǎng)站相關(guān)的所有Cookie信息提交給網(wǎng)站服務(wù)器域庇。

<2>設(shè)置Cookie

? 可以通過HttpResponse對象中的set_cookie方法來設(shè)置cookie嵌戈。

HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)

? ? ? max_age 單位為秒覆积,默認(rèn)為None。

? ? ? 如果是臨時cookie熟呛,可將max_age設(shè)置為None宽档。

? 示例:

def demo_view(request):

? ? response = HttpResponse('ok')

? ? response.set_cookie('0001', 'python1')? # 臨時cookie

? ? response.set_cookie('0002', value='python2', max_age=3600)? # 有效期一小時

? ? return response

<3>獲取Cookie

? 可以通過HttpRequest對象的COOKIES屬性來讀取本次請求攜帶的cookie值。request.COOKIES為字典類型庵朝。

? request.COOKIES.get('key')

def demo_view(request):

? ? cookie1 = request.COOKIES.get('0001')

? ? print(cookie1)

? ? return HttpResponse('OK')

4.Session

<1>啟用Session

? 1>Session簡介:

? ? ? 在計算機中吗冤,尤其是在網(wǎng)絡(luò)應(yīng)用中,稱為“會話控制”偿短。Session 對象存儲特定用戶會話所需的屬性及配置信息欣孤。這樣,當(dāng)用戶在應(yīng)用程序的 Web 頁之間跳轉(zhuǎn)時昔逗,存儲在 Session 對象中的變量將不會丟失降传,而是在整個用戶會話中一直存在下去。當(dāng)用戶請求來自應(yīng)用程序的 Web 頁時勾怒,如果該用戶還沒有會話婆排,則 Web 服務(wù)器將自動創(chuàng)建一個 Session 對象。當(dāng)會話過期或被放棄后笔链,服務(wù)器將終止該會話段只。Session 對象最常見的一個用法就是存儲用戶的首選項。例如鉴扫,如果用戶指明不喜歡查看圖形赞枕,就可以將該信息存儲在 Session 對象中。注意 會話狀態(tài)僅在支持 cookie 的瀏覽器中保留坪创。

? 2>Session的理解:

? ? ? 廣義來講: session是一種會話機制, 用于記錄多次http請求之間的關(guān)系,關(guān)系就是狀態(tài)數(shù)據(jù),比如登錄狀態(tài).

? ? ? 狹義來講: session是一種會話數(shù)據(jù), 記錄的狀態(tài)數(shù)據(jù), 比如登錄之后記錄的user_id等

? 3>Django項目默認(rèn)啟用Session

? ? ? 可以在settings.py文件的中間件選項中查看炕婶,如圖所示

? ? ? 如需禁用session,將上圖中的session中間件注釋掉即可莱预。

<2>存儲方式

? 在settings.py文件中柠掂,可以設(shè)置session數(shù)據(jù)的存儲方式.

? 另外session可以保存在數(shù)據(jù)庫、本地緩存( 程序的運行內(nèi)存中, 全局變量)依沮、文件涯贞、redis等 。

? 1>數(shù)據(jù)庫

? ? ? 存儲在數(shù)據(jù)庫中危喉,如下設(shè)置可以寫到settings中宋渔,也可以不寫,這是默認(rèn)存儲方式辜限。

# 如果是存放數(shù)據(jù)庫, 一般以db結(jié)尾

SESSION_ENGINE='django.contrib.sessions.backends.db'

? ? ? 如果存儲在數(shù)據(jù)庫中傻谁,需要在項INSTALLED_APPS中安裝Session應(yīng)用。

? ? ? 數(shù)據(jù)庫中的表如圖所示

? ? ? 表結(jié)構(gòu)如下

? ? ? 由表結(jié)構(gòu)可知列粪,操作Session包括三個數(shù)據(jù):鍵审磁,值,過期時間岂座。

? 2>本地緩存

? ? ? 存儲在本機內(nèi)存中态蒂,如果丟失則不能找回,比數(shù)據(jù)庫的方式讀寫更快费什。

# 如果是存放在本地緩存, 一般以cache結(jié)尾

SESSION_ENGINE='django.contrib.sessions.backends.cache'

? ? ? 其中,本地緩存會出現(xiàn)問題: 因為是存放在本地的內(nèi)存中,所以會出現(xiàn)在脫機情況下出現(xiàn)的跨機訪問問題:

? ? ? ? ? ■ 我們這里可以看到: 有兩臺服務(wù)器存儲的有session數(shù)據(jù), 前面由nginx負(fù)責(zé)管理訪問機制,有可能現(xiàn)在的訪問方式是輪詢形式, 那么意味著第一次用戶進入的是上面的服務(wù)器,進行了登錄操作,我們把他的登錄狀態(tài)保存到了服務(wù)器1里面, 隨后用戶有進行了其他操作, 然后有登陸進入這個服務(wù)器,這次輪詢到了服務(wù)器2里面,但是這里面沒有保存登錄狀態(tài),這樣就會造成用戶第二次登錄.所以會造成用戶跨機的問題.

? ? ? ? ? ■ 但是如果我們使用redis就不會出現(xiàn)這樣的情況,因為無論是哪一個服務(wù)器,最終存儲的數(shù)據(jù)都保存到了redis中 :

? 3>混合存儲

? ? ? 優(yōu)先從本機內(nèi)存中存取钾恢,如果沒有則從數(shù)據(jù)庫中存取。

# 如果是存放數(shù)據(jù)庫,一般以cached_db結(jié)尾

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

? 4>Redis

? ? ? django-redis 中文文檔: http://django-redis-chs.readthedocs.io/zh_CN/latest/#cache-backend

? ? ? 在redis中保存session鸳址,需要引入第三方擴展瘩蚪,我們可以使用django-redis來解決。

? ? ? 安裝擴展

pip install django-redis

? ? ? 在settings.py文件中做如下設(shè)置

CACHES = {

? ? "default": {

? ? ? ? "BACKEND": "django_redis.cache.RedisCache",

? ? ? ? # 定義django中redis的位置

? ? ? ? "LOCATION": "redis://127.0.0.1:6379/0",

? ? ? ? "OPTIONS": {

? ? ? ? ? ? # django使用redis的默認(rèn)客戶端來進行操作.

? ? ? ? ? ? "CLIENT_CLASS": "django_redis.client.DefaultClient",

? ? ? ? }

? ? }

}

# 我們定義一個cache(本地緩存來存儲信息,cache指定的是redis)

SESSION_ENGINE = "django.contrib.sessions.backends.cache"

# 本地的session使用的本地緩存名稱是'default', 這個名稱就是上面我們配置的caches的名

# 稱"default"

SESSION_CACHE_ALIAS = "default"

? ? ? 添加代碼,查看是否能夠存儲到redis中去:

urls.py:

# url的配置:

from django.conf.urls import url

from . import views

urlpatterns = [

? ? # 保存session數(shù)據(jù)

? ? url(r'^set_session', views.set_session),

? ? # 獲取session數(shù)據(jù)

? ? url(r'^get_session', views.get_session),

]

Views.py:

# 定義設(shè)置session的視圖函數(shù)

def set_session(request):

? ? request.session['one'] = '1'

? ? request.session['two'] = '2'

? ? request.session['three'] = '3'

? ? return HttpResponse('保存session數(shù)據(jù)成功')

# 定義獲取session的視圖函數(shù)

def get_session(request):

? ? ? one = request.session.get('one')

? ? ? two = request.session.get('two')

? ? ? three = request.session.get('three')

? ? ? text = 'one=%s, two=%s, three=%s' % (one,two,three)

? ? ? return HttpResponse(text)

? ? ? 打開redis來查看存儲的信息:

打開redis:

redis-server

查看信息: (在新窗口中)

redis-cli

select 1

keys *

<3>Session操作

? 通過HttpRequest對象的session屬性進行會話的讀寫操作稿黍。

? 1>設(shè)置session

? ? ? 以鍵值對的格式寫session

? ? ? request.session['鍵']=值

例如: request.session['one'] = '1'

? 2>獲取session

? ? ? 根據(jù)鍵讀取值

? ? ? request.session.get('鍵')

例如: one = request.session.get('one')

? 3>清除所有session疹瘦,在存儲中刪除值部分

request.session.clear()

? 4>清除session數(shù)據(jù),在存儲中刪除session的整條數(shù)據(jù)巡球。

request.session.flush()

? 5>刪除session中的指定鍵及值言沐,在存儲中只刪除某個鍵及對應(yīng)的值。

del request.session['鍵']

? 6>設(shè)置session的有效期

request.session.set_expiry(value)

? ? ? 如果value是一個整數(shù)酣栈,session將在value秒沒有活動后過期险胰。

? ? ? 如果value為0,那么用戶session的Cookie將在用戶的瀏覽器關(guān)閉時過期矿筝。

? ? ? 如果value為None起便,那么session有效期將采用系統(tǒng)默認(rèn)值,默認(rèn)為兩周窖维,可以通過在settings.py中設(shè)置SESSION_COOKIE_AGE來設(shè)置全局默認(rèn)值榆综。其中 SESSION_COOKIE_AGE的單位是以秒為單位的.

5.類視圖

<1>類視圖

? 1>視圖函數(shù)

? ? ? 以函數(shù)的方式定義的視圖稱為函數(shù)視圖,即我們常說的視圖函數(shù)

? 2>視圖函數(shù)的缺點

? ? ? 視圖函數(shù)遭遇不同方式分別請求( 例如 get 和 post )陈辱,并且需要做不同處理時换淆,我們?nèi)绻谝粋€函數(shù)中編寫不同的業(yè)務(wù)邏輯,代碼可讀性和復(fù)用性都不好

? 3>類視圖

? ? ? 使用類來定義的視圖绿贞,稱為類視圖

? ? ? 類視圖中的方法通常以請求方式命名

? ? ? 在Django中給我們提供了類視圖的概念废登,即可以使用類來定義一個視圖,解決了視圖函數(shù)的缺點

<2>類視圖使用

? 1>如果想要使用類視圖需要如下幾步:

? ? ? 定義類視圖, 且類視圖繼承自View

? ? ? ? ? ■ 使用: from django.views.generic import View

? ? ? ? ? ■ 或者是: from django.views.generic.base import View

? ? ? 定義路由利赋,路由的第二個參數(shù)需要是一個函數(shù)水评,所以我們會調(diào)用系統(tǒng)的 as_view() 方法

urlpatterns = [

? ? # 類視圖:注冊

? ? # url(路徑, 執(zhí)行的函數(shù))

? ? # url的第二個參數(shù)需要是一個函數(shù)

? ? # 我們這里如果傳入: views.RegisterView 會發(fā)現(xiàn)這個是一個類, 不是一個函數(shù),

? ? # 所以我們需要調(diào)用系統(tǒng)給我們提供的 as_view() 方法

? ? url(r'^register/$', views.RegisterView.as_view()),

]

? ? ? 使用瀏覽器訪問我們定義的路由, 查看結(jié)果

? 2>使用類視圖可以將視圖對應(yīng)的不同請求方式以類中的不同方法來區(qū)別定義

如下所示:

# 導(dǎo)入類視圖的父類View

from django.views.generic import View

class RegisterView(View):

? ? """類視圖:處理注冊"""

? ? def get(self, request):

? ? ? ? """處理GET請求,返回注冊頁面"""

? ? ? ? return render(request, 'register.html')

? ? def post(self, request):

? ? ? ? """處理POST請求媚送,實現(xiàn)注冊邏輯"""

? ? ? ? return HttpResponse('這里實現(xiàn)注冊邏輯')

? 3>類視圖的好處:

? ? ? 代碼可讀性好

? ? ? 類視圖相對于函數(shù)視圖有更高的復(fù)用性

? ? ? 如果其他地方需要用到某個類視圖的某個特定邏輯中燥,直接繼承該類視圖即可

? 4>注意:

? ? ? 如果我們在類視圖函數(shù)中沒有定義方法, 但是我們請求了. 會報405找不到請求方法的錯誤.

? ? ? ? ? ■ 例如: 類視圖中沒有定義get方法, 但是我們使用get方法進行了請求, 那么會報405的錯誤: 找不到對應(yīng)的請求方法.

? ? ? 在類視圖中定義的get或者是post都是對象方法, 第一個參數(shù)都是self.

? ? ? 第二個參數(shù)一般情況下都是 request對象. 其他的參數(shù)依次往后面寫就可以.

? ? ? 我們在使用類視圖的時候, 需要在路由位置進行設(shè)置, 設(shè)置的第二個參數(shù)需要是一個函數(shù), 所以我們這里調(diào)用了類以后, 后面需要調(diào)用 as_view( ) 函數(shù).

<3>類視圖原理

? 為什么我們定義url的時候, 調(diào)用 as_view() 函數(shù),就可以達到結(jié)果, 如果不調(diào)用就會報錯

? as_view()的原理

? ? ? 由源碼可看出as_view()的作用是返回真正的視圖函數(shù)

? ? @classonlymethod

? ? def as_view(cls, **initkwargs):

? ? ? ? ...省略代碼...

? ? ? ? def view(request, *args, **kwargs):

? ? ? ? ? ? # 這里的cls是as_view這個函數(shù)接收的第一個參數(shù),也就是調(diào)用當(dāng)前函數(shù)的類

? ? ? # 得到調(diào)用的類了之后, 創(chuàng)建類的對象: self

? ? ? ? ? ? self = cls(**initkwargs)

? ? ? ? ? ? if hasattr(self, 'get') and not hasattr(self, 'head'):

? ? ? ? ? ? ? ? self.head = self.get

? ? ? ? ? ? # 給當(dāng)前這個類,添加對應(yīng)的屬性, 如下所示:

? ? ? ? ? ? self.request = request

? ? ? ? ? ? self.args = args

? ? ? ? ? ? self.kwargs = kwargs

? ? ? ? ? ? # 調(diào)用dispatch方法,按照不同請求方式調(diào)用不同請求方法

? ? ? ? ? ? return self.dispatch(request, *args, **kwargs)

? ? ? ? ...省略代碼...

? ? ? ? # 返回真正的函數(shù)視圖

? ? ? ? return view

? ? # dispatch本身是分發(fā)的意思,這里指的是函數(shù)的名字.

? ? def dispatch(self, request, *args, **kwargs):

? ? ? ? # self.http_method_names指的是我們的類視圖中方法的名字

? ? ? ? ? ? ? # 這里把所有方法的名字都存放在了http_methods_names中

? ? ? ? ? ? ? # 我們會把當(dāng)前請求的方式轉(zhuǎn)為小寫,然后判斷是否在列表中存在.

? ? ? ? if request.method.lower() in self.http_method_names:

? ? ? ? ? ? """

? ? 如果在里面, 則進入這里

? ? 這里的getattr作用是獲取當(dāng)前對象的屬性.

? ? 下面的參數(shù)為:

? ? self :? 類視圖對象

? ? request.method.lower() : 請求方法的小寫. 例如: 'get' 或 'post'

? ? http_method_not_allowed : 后續(xù)處理方式(不允許請求)

? ? 下面代碼整體的意思: 根據(jù)類視圖對象, 獲取當(dāng)前類視圖中對應(yīng)名稱的方法

? ? 如果獲取到, 則把方法返回給handle, 否則不允許訪問.

? ? """

? handler = getattr(self, request.method.lower(), self.http_method_not_allowed)

else:

? ? ? ? ? # 如果類視圖中如果沒有的話, 則進入這里, 表明不允許進行請求.

? ? ? ? ? ? # 我們會把不允許請求這個字段返回給handle.

? ? ? ? ? handler = self.http_method_not_allowed

? ? ? # 最終返回handle(handle里面要么包含可以訪問的方法, 要么就是不允許訪問的字段)

? ? ? return handler(request, *args, **kwargs)

<4>類視圖使用裝飾器

? 先定義一個為函數(shù)視圖準(zhǔn)備的裝飾器(在設(shè)計裝飾器時基本都以函數(shù)視圖作為考慮的被裝飾對象)塘偎,以及一個要被裝飾的類視圖

#? 定義一個裝飾器

def my_decorator(func):

? ? # wrapper函數(shù)必然會接收一個request對象,因為傳入進來的func這個函數(shù)肯定會帶這個參數(shù)

? ? def wrapper(request, *args, **kwargs):

? ? ? ? print('自定義裝飾器被調(diào)用了')

? ? ? ? print('請求路徑%s' % request.path)

? ? ? ? return func(request, *args, **kwargs)

? ? return wrapper

# 我們定義的類視圖

class DemoView(View):

? ? # 我們給get方法添加上裝飾器, 然后執(zhí)行.

? ? @my_decorator

? ? def get(self, request):

? ? ? ? print('get方法')

? ? ? ? return HttpResponse('ok')

? ? # 類視圖里面的對象方法: post方法

? ? def post(self, request):

? ? ? ? print('post方法')

? ? ? ? return HttpResponse('ok')

? 把一個修飾函數(shù)的裝飾器作用在類上的幾種方法

? 1>在URL配置中裝飾

? ? ? url配置中使用 as_view( ) 函數(shù)返回一個view( ) 函數(shù)

? ? ? 換句話說在調(diào)用類視圖之前疗涉,必然會調(diào)用 view( ) 這個函數(shù)拿霉,所以把裝飾器作用到 view( ) 函數(shù)上

# 導(dǎo)入views.py視圖文件

from . import views

urlpatterns = [

? ? # 我們在路由部分, 把定義好的裝飾器添加到當(dāng)前的函數(shù)上

? ? # 這里需要注意: as_view() 會返回一個 view() 函數(shù)

? ? # 所以我們把裝飾器添加到view()函數(shù)上

? ? url(r'^demo/$', views.my_decorate(views.DemoView.as_view()))

]

? ? ? 這種方式的弊端

? ? ? ? ? ■ 此種方式最簡單,但因裝飾行為被放置到了url配置中咱扣,單看視圖的時候無法知道此視圖還被添加了裝飾器绽淘,不利于代碼的完整性,不建議使用闹伪。

? ? ? ? ? ■ 此種方式會為類視圖中的所有請求方法都加上裝飾器行為(因為是在視圖入口處沪铭,分發(fā)請求方式前)。

? 2>在類視圖中使用裝飾器

? ? ? 因為裝飾器的內(nèi)函數(shù)第一個參數(shù)是request偏瓤,而類視圖里面的函數(shù)第一個參數(shù)是self杀怠,第二個參數(shù)才是request。所以我們不能夠直接給類視圖中的函數(shù)添加裝飾器厅克,否則傳入的參數(shù)會出現(xiàn)錯誤

? ? ? 解決方法:

? 由上面的案例我們可知: 我們定義的裝飾器不能夠直接使用到類視圖的方法上.

? 所以我們需要把我們定義的裝飾器進行轉(zhuǎn)化, 轉(zhuǎn)化為能夠被類視圖中函數(shù)使用的裝飾器

? 轉(zhuǎn)化的方法需要導(dǎo)入:

? from django.utils.decorators import method_decorator

? 導(dǎo)入進來之后, 我們需要把自定義的裝飾器用這個方法包裹住轉(zhuǎn)化, 例如:

? @method_decorator(自定義裝飾器)

? ? ? 第一種解決方式:

? 在類視圖中使用為函數(shù)視圖準(zhǔn)備的裝飾器時赔退,不能直接添加裝飾器

? 需要使用method_decorator將其轉(zhuǎn)換為適用于類視圖方法的裝飾器。

from django.views.generic import View

# 導(dǎo)入轉(zhuǎn)換的裝飾器方法:

from django.utils.decorators import method_decorator

# 為特定請求方法添加裝飾器

class DemoView(View):

? ? # 使用轉(zhuǎn)換的方法將裝飾器轉(zhuǎn)化:

? ? @method_decorator(my_decorator)

? ? def get(self, request):

? ? ? ? print('get方法')

? ? ? ? return HttpResponse('ok')

? ? def post(self, request):

? ? ? ? print('post方法')

? ? ? ? return HttpResponse('ok')

? 問題:

? ? ? 雖然上面的方式可以解決類視圖添加裝飾器問題, 但是我們這種是給單個函數(shù)添加的, 而不是類視圖中的所有函數(shù)

? ? ? 第二種解決方式:

? 重寫dispatch方法已骇,給dispatch方法加裝飾器

? 使用method_decorator將其轉(zhuǎn)換為適用于類視圖方法的裝飾器

from django.views.generic import View

from django.http import HttpResponse

from django.utils.decorators import method_decorator

# 自定義的裝飾器方法

def my_decorator(func):

? ? def wrapper(request, *args, **kwargs):

? ? ? ? print('自定義裝飾器被調(diào)用了')

? ? ? ? print('請求的路徑:%s' % request.path)

? ? ? ? return func(request, *args, **kwargs)

? ? return wrapper

# 類視圖

class DemoView(View):

? ? # 重寫父類的dispatch方法, 因為這個方法被 as_view() 中的 view() 調(diào)用

? ? ? # 所以我們對這個方法添加裝飾器, 也就相當(dāng)于對整個類視圖的方法添加裝飾器.

? ? ? @method_decorator(my_decorator)

? ? def dispatch(self, request, *args, **kwargs):

? ? ? ? # 重寫父類的這個方法我們不會修改它的任何參數(shù), 所以我們直接調(diào)用父類的這個方法即可

? ? ? ? # 它里面的參數(shù)我們也不動它, 直接還傳遞過去.

? ? ? ? return super().dispatch(request, *args, **kwargs)

? ? def get(self, request):

? ? ? ? print('get')

? ? ? ? return HttpResponse('getfunc ok')

? ? def post(self, request):

? ? ? ? print('post')

? ? ? ? return HttpResponse('postfunc ok')

? ? ? 第三種解決方式:

? ? ? ? ? ■ method_decorator( )方法直接裝飾到類上去离钝,使當(dāng)前的視圖類中的某一個函數(shù)添加裝飾器方法

from django.views.generic import View

from django.http import HttpResponse

from django.utils.decorators import method_decorator

def my_decorator(func):

? ? def wrapper(request, *args, **kwargs):

? ? ? ? print('自定義裝飾器被調(diào)用了')

? ? ? ? print('請求的路徑:%s' % request.path)

? ? ? ? return func(request, *args, **kwargs)

? ? return wrapper

"""

類視圖

給類視圖增加上@method_decorator方法

增加上之后,并不能夠給其中的某一個函數(shù)增加上裝飾器

所以我們需要給method_decator配置第二個參數(shù)

第二個參數(shù)就是類中某一個函數(shù)的名稱褪储,意味著給當(dāng)前這個函數(shù)增加上裝飾器

"""

@method_decorator(my_decorator, name='get')

class DemoView(View):

? ? @method_decorator(my_decorator)

? ? def dispatch(self, request, *args, **kwargs):

? ? ? ? return super().dispatch(request, *args, **kwargs)

? ? def get(self, request):

? ? ? ? print('get')

? ? ? ? return HttpResponse('getfunc ok')

? ? def post(self, request):

? ? ? ? print('post')

? ? ? ? return HttpResponse('postfunc ok')

? ? ? 第四種解決方式:

? ? ? ? ? ■ 使用@method_decorator在類視圖的位置給'dispatch'方法添加裝飾器

from django.views.generic import View

from django.http import HttpResponse

from django.utils.decorators import method_decorator

def my_decorator(func):

? ? def wrapper(request, *args, **kwargs):

? ? ? ? print('自定義裝飾器被調(diào)用了')

? ? ? ? print('請求的路徑:%s' % request.path)

? ? ? ? return func(request, *args, **kwargs)

? ? return wrapper

# 類視圖

# 因為我們可以直接給dispatch方法添加裝飾器,意味著, 我們內(nèi)部不用重寫dispatch方法了.

@method_decorator(my_decorator, name='dispatch')

class DemoView(View):

? ? def get(self, request):

? ? ? ? print('get')

? ? ? ? return HttpResponse('getfunc ok')

? ? def post(self, request):

? ? ? ? print('post')

? ? ? ? return HttpResponse('postfunc ok')

? 3>method_decorator裝飾器的作用

? ? ? 為函數(shù)視圖準(zhǔn)備的裝飾器卵渴,其被調(diào)用時,第一個參數(shù)用于接收request對象

def my_decorate(func):

? ? def wrapper(request, *args, **kwargs):? # 第一個參數(shù)request對象

? ? ? ? ...代碼省略...

? ? ? ? return func(request, *args, **kwargs)

? ? return wrapper

? ? ? 而類視圖中請求方法被調(diào)用時鲤竹,傳入的第一個參數(shù)不是request對象浪读,而是self 視圖對象本身,第二個位置參數(shù)才是request對象

class DemoView(View):

? ? def dispatch(self, request, *args, **kwargs):

? ? ? ? ...代碼省略...

? ? def get(self, request):

? ? ? ? ...代碼省略...

? ? ? 所以如果直接將用于函數(shù)視圖的裝飾器裝飾類視圖方法辛藻,會導(dǎo)致參數(shù)傳遞出現(xiàn)問題碘橘。

? ? ? method_decorator裝飾器的作用是為函數(shù)視圖裝飾器補充第一個self參數(shù),以適配類視圖方法吱肌。

? 4>類視圖使用裝飾器的最終方法

? ? ? 將裝飾器本身改為可以適配類視圖方法

def my_decorator(func):

? ? def wrapper(self, request, *args, **kwargs):? # 此處增加了self

? ? ? ? print('自定義裝飾器被調(diào)用了')

? ? ? ? print('請求路徑%s' % request.path)

? ? ? ? return func(self, request, *args, **kwargs)? # 此處增加了self

? ? return wrapper

<5>構(gòu)造Mixin擴展類

? 1>給類視圖所有方法添加裝飾器有兩種

? ? ? 修改裝飾器接收到的參數(shù)

? ? ? ? ? ■ 即把裝飾器的第一個參數(shù)修改為self痘拆,使類中所有的方法都可以直接添加上裝飾器

? ? ? 修改類視圖中所有函數(shù)都會調(diào)用的 as_view() 方法

? ? ? ? ? ■ 或者是 dispatch方法, 因為dispatch方法在 as_view() 方法內(nèi)部,故我們這里不討論dispatch

? 2>使用類擴展的形式給當(dāng)前的類視圖添加裝飾器

? ? ? 也就是說,把裝飾器加在類擴展中氮墨,在類視圖的父類中重寫as_view()方法纺蛆,并繼承自View類的as_view()方法

? ? ? View類的as_view()方法返回了view(),給view()添加裝飾器

? ? ? 那么我們可以繼續(xù)思考

類視圖 —————> 繼承自View類 (包含有as_view函數(shù))

? ? ? 如果我們在整個繼承的過程中添加一步, 例如:

類視圖 ———> 繼承自額外擴展的類 ———> 繼承自View類(包含有as_view函數(shù))

? ? ? 在額外擴展的類中重寫 as_view( ) 方法规揪,并且對 as_view( ) 方法添加裝飾器桥氏,類視圖中的所有方法都會被裝飾器裝飾

? ? ? ? ? ■ 第一步:創(chuàng)建一個擴展類,在擴展類中重寫 as_view 方法猛铅,并且給父類傳過來的view方法添加裝飾器

? ? ? ? ? ■ 第二步:讓類視圖繼承自擴展類

? ? ? 第一步代碼:

# 定義一個新的擴展類,讓該類繼承自View類

class BaseView(View):

? ? # 在擴展類中,重寫View類的 as_view 方法, 并且對該方法添加裝飾器

? ? @classmethod

? ? def as_view(cls, *args, **kwargs):

? ? ? ? # 重寫之后, 不對該方法做其他額外操作,所以我們重新調(diào)用父類的該方法

? ? ? ? view = super().as_view(*args, **kwargs)

? ? ? ? # 對父類傳過來的view方法添加裝飾器

? ? ? ? view = my_decorator(view)

? ? ? ? return view

? ? ? 第二步代碼:

# 讓我們的類視圖繼承自擴展類

class DemoView(BaseView):

? ? def get(self, request):

? ? ? ? print('get')

? ? ? ? return HttpResponse('get func')

? ? def post(self, request):

? ? ? ? print('post')

? ? ? ? return HttpResponse('post func')

? 結(jié)論:

? ? ? 經(jīng)過中間一層額外擴展類的裝飾過濾字支,我們原來的DemoView中的所有視圖方法是能夠經(jīng)過裝飾器的

? 3>使用多個類擴展的形式給當(dāng)前的類視圖添加多個裝飾器

? ? ? 那么我們可以繼續(xù)思考:

類視圖 —————> 繼承自View類 (包含有as_view函數(shù))

類視圖 ———> 繼承自額外擴展的類1 ---> 繼承自額外擴展的類2 ———> 繼承自View類(包含有as_view函數(shù))

? ? ? 延伸:

我們定義兩個擴展類, 并且重寫兩次 as_view 方法, 來看看會發(fā)生什么 :

from django.views.generic import View

from django.http import HttpResponse

from django.utils.decorators import method_decorator

# 定義的第一個裝飾器:

def my_decorator(func):

? ? def wrapper(request, *args, **kwargs):

? ? ? ? print('自定義裝飾器被調(diào)用了')

? ? ? ? print('請求的路徑:%s' % request.path)

? ? ? ? return func(request, *args, **kwargs)

? ? return wrapper

# 定義的第二個裝飾器:

def my_decorator2(func):

? ? def wrapper(request, *args, **kwargs):

? ? ? ? print('自定義裝飾器被調(diào)用了22222')

? ? ? ? print('請求的路徑:%s' % request.path)

? ? ? ? return func(request, *args, **kwargs)

? ? return wrapper

# 額外增加的第一個擴展類

class BaseView(View):

? ? # 第一次重寫父類中的as_view方法

? ? @classmethod

? ? def as_view(cls, *args, **kwargs):

? ? ? ? view = super().as_view(*args, **kwargs)

? ? ? ? # 對獲取的view第一次添加裝飾器

? ? ? ? view = my_decorator(view)

? ? ? ? return view

# 額外增加的第二個擴展類

class Base2View(View):

? ? # 第二次重寫父類中的as_view方法

? ? @classmethod

? ? def as_view(cls, **initkwargs):

? ? ? ? view = super().as_view(**initkwargs)

? ? ? ? # 對獲取的view進行第二次添加裝飾器

? ? ? ? view = my_decorator2(view)

? ? ? ? return view

# 我們定義的類視圖, 繼承自兩個額外增加的類

class DemoView(BaseView, Base2View):

? ? # 類視圖中的get方法

? ? def get(self, request):

? ? ? ? print('get')

? ? ? ? return HttpResponse('get func')

? ? # 類視圖中的post方法

? ? def post(self, request):

? ? ? ? print('post')

? ? ? ? return HttpResponse('post func')

? 那么我們來看一下同時調(diào)用兩個裝飾器是怎樣實現(xiàn)的:

? 說明:

? ? ? 如果兩個擴展類的父類相同:則兩個父類都會調(diào)用

? ? ? 如果兩個擴展類的父類不同:則只會調(diào)用第一個父類

? 綜上,我們可以把代碼變成這個樣子:

? ? ? 為什么BaseView類和Base2View類都繼承自object還能重寫as_view()?

? ? ? ? ? ■ 當(dāng)程序運行到BaseView類的view = super().as_view(*args, **kwargs)時堕伪,會在父類中查找as_view()揖庄,如果沒找到會去Base2View類中以及父類中查找,如果還沒有會去View類中查找欠雌,再沒有就會報錯了抠艾。

# 第一個擴展類, 讓他繼承自object

class BaseView(object):

? ? @classmethod

? ? def as_view(cls, *args, **kwargs):

? ? ? ? view = super().as_view(*args, **kwargs)

? ? ? ? view = my_decorator(view)

? ? ? ? return view

# 第二個擴展類,讓他繼承自object

class Base2View(object):

? ? @classmethod

? ? def as_view(cls, *args, **kwargs):

? ? ? ? view = super().as_view(*args, **kwargs)

? ? ? ? view = my_decorator2(view)

? ? ? ? return view

# 類視圖, 讓他除了繼承自這兩個父類外, 最后繼承View類.

class DemoView(BaseView, Base2View, View):

? ? def get(self, request):

? ? ? ? print('get方法')

? ? ? ? return HttpResponse('ok')

? ? def post(self, request):

? ? ? ? print('post方法')

? ? ? ? return HttpResponse('ok')

? 說明:

? ? ? 因為都是繼承自object,所以擴展類中的super.as_view都會去找其他的父類依次執(zhí)行桨昙,最終都會執(zhí)行到View這個類這里,所以肯定會執(zhí)行View中的as_view方法

? ? ? 使用Mixin擴展類腌歉,也會為類視圖的所有請求方法都添加裝飾行為蛙酪。

6.中間件

? 中間件類似請求鉤子

? Django中的中間件是一個輕量級、底層的插件系統(tǒng)翘盖,可以介入Django的請求和響應(yīng)處理過程桂塞,修改Django的輸入或輸出。中間件的設(shè)計為開發(fā)者提供了一種無侵入式的開發(fā)方式馍驯,增強了Django框架的健壯性阁危。

? 我們可以使用中間件,在Django處理視圖的不同階段對輸入或輸出進行干預(yù)汰瘫。

<1>中間件的定義方法

? 1>定義中間件的步驟

? ? ? 在一個子應(yīng)用中創(chuàng)建一個中間件文件狂打,例如: middleware(別的名字也可以)

? ? ? ? ? ■ 在中間件文件中定義一個中間件工廠函數(shù),然后返回一個可以調(diào)用的中間件混弥。

? ? ? ? ? ■ 中間件工廠函數(shù)需要接收一個可以調(diào)用的get_response對象趴乡。這個函數(shù)接收的參數(shù)只能是get_response

? ? ? ? ? ■ 返回的中間件也是一個可以被調(diào)用的對象,并且像視圖一樣需要接收一個request對象參數(shù)蝗拿,返回一個response對象晾捏。

? ? ? 在setting.py文件的MIDDLEWARE部分注冊添加

? ? ? 在調(diào)用視圖時,便會調(diào)用中間件了

? 2>中間件模板

? ? ?

def simple_middleware(get_response):

? ? # 此處編寫的代碼僅在Django第一次配置和初始化的時候執(zhí)行一次哀托。

? ? def middleware(request):

? ? ? ? # 此處編寫的代碼會在每個請求處理視圖前被調(diào)用惦辛。

? ? ? ? response = get_response(request)

? ? ? ? # 此處編寫的代碼會在每個請求處理視圖之后被調(diào)用。

? ? ? ? return response

? ? return middleware

? 3>定義中間件的案例

? ? ? 在子應(yīng)用users中新建一個中間件文件middleware.py

? ? ? ? ? ■ 在中間件文件中定義一個中間件工廠函數(shù)

def my_middleware(get_response):

? ? print('init 被調(diào)用')

? ? def middleware(request):

? ? ? ? print('before request 被調(diào)用')

? ? ? ? response = get_response(request)

? ? ? ? print('after response 被調(diào)用')

? ? ? ? return response

? ? return middleware

? ? ? 定義好中間件后仓手,需要在工程同名應(yīng)用下的settings.py文件中添加注冊中間件

? ? ? ? ? ■ 子應(yīng)用名.中間件文件名.中間件工廠函數(shù)名

? ? ? ? ? ■ 'users.middleware.my_middleware'

MIDDLEWARE = [

? ? 'django.middleware.security.SecurityMiddleware',

? ? 'django.contrib.sessions.middleware.SessionMiddleware',

? ? 'django.middleware.common.CommonMiddleware',

? ? # 'django.middleware.csrf.CsrfViewMiddleware',

? ? 'django.contrib.auth.middleware.AuthenticationMiddleware',

? ? 'django.contrib.messages.middleware.MessageMiddleware',

? ? 'django.middleware.clickjacking.XFrameOptionsMiddleware',

? ? 'users.middleware.my_middleware',? # 添加中間件

]

? ? ? 定義一個視圖進行測試

def demo_view(request):

? ? print('view 視圖被調(diào)用')

? ? return HttpResponse('OK')

? 注意:Django運行在調(diào)試模式下胖齐,中間件init部分有可能被調(diào)用兩次,關(guān)閉調(diào)試模式只會運行一次

<2>多個中間件的執(zhí)行順序

? 在請求視圖被處理前俗或,中間件由上至下依次執(zhí)行

? 在請求視圖被處理后市怎,中間件由下至上依次執(zhí)行

? 1>定義兩個中間件

def my_middleware(get_response):

? ? print('init 被調(diào)用')

? ? def middleware(request):

? ? ? ? print('before request 被調(diào)用')

? ? ? ? response = get_response(request)

? ? ? ? print('after response 被調(diào)用')

? ? ? ? return response

? ? return middleware

def my_middleware2(get_response):

? ? print('init2 被調(diào)用')

? ? def middleware(request):

? ? ? ? print('before request 2 被調(diào)用')

? ? ? ? response = get_response(request)

? ? ? ? print('after response 2 被調(diào)用')

? ? ? ? return response

? ? return middleware

? 2>注冊添加兩個中間件

MIDDLEWARE = [

? ? 'django.middleware.security.SecurityMiddleware',

? ? 'django.contrib.sessions.middleware.SessionMiddleware',

? ? 'django.middleware.common.CommonMiddleware',

? ? # 'django.middleware.csrf.CsrfViewMiddleware',

? ? 'django.contrib.auth.middleware.AuthenticationMiddleware',

? ? 'django.contrib.messages.middleware.MessageMiddleware',

? ? 'django.middleware.clickjacking.XFrameOptionsMiddleware',

? ? 'users.middleware.my_middleware',? # 添加

? ? 'users.middleware.my_middleware2',? # 添加

]

? 3>執(zhí)行結(jié)果

init2 被調(diào)用

init 被調(diào)用

before request 被調(diào)用

before request 2 被調(diào)用

view 視圖被調(diào)用

after response 2 被調(diào)用

after response 被調(diào)用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辛慰,隨后出現(xiàn)的幾起案子区匠,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驰弄,死亡現(xiàn)場離奇詭異麻汰,居然都是意外死亡,警方通過查閱死者的電腦和手機戚篙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門五鲫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人岔擂,你說我怎么就攤上這事位喂。” “怎么了乱灵?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵塑崖,是天一觀的道長。 經(jīng)常有香客問我痛倚,道長规婆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任蝉稳,我火速辦了婚禮抒蚜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘耘戚。我一直安慰自己嗡髓,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布毕莱。 她就那樣靜靜地躺著器贩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪朋截。 梳的紋絲不亂的頭發(fā)上蛹稍,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機與錄音部服,去河邊找鬼唆姐。 笑死,一個胖子當(dāng)著我的面吹牛廓八,可吹牛的內(nèi)容都是我干的奉芦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼剧蹂,長吁一口氣:“原來是場噩夢啊……” “哼声功!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宠叼,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤先巴,失蹤者是張志新(化名)和其女友劉穎其爵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伸蚯,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡摩渺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了剂邮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摇幻。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖挥萌,靈堂內(nèi)的尸體忽然破棺而出绰姻,到底是詐尸還是另有隱情,我是刑警寧澤引瀑,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布龙宏,位于F島的核電站,受9級特大地震影響伤疙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辆影,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一徒像、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛙讥,春花似錦锯蛀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至迫像,卻和暖如春劈愚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闻妓。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工菌羽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人由缆。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓注祖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親均唉。 傳聞我的和親對象是個殘疾皇子是晨,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容