日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Django(五)中间件

發(fā)布時(shí)間:2025/3/17 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Django(五)中间件 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一次請(qǐng)求的生命周期

我們先看客戶端發(fā)起一次http請(qǐng)求的流程

注:django框架不包括socket, 要借助圖中的兩個(gè)模塊來(lái)實(shí)現(xiàn)socket,進(jìn)行客戶端和服務(wù)端通信。wsgi性能較弱,一般測(cè)試開發(fā)用;企業(yè)中用uwsgi,性能強(qiáng),并發(fā)好。

中間件

從圖上可知,請(qǐng)求在到達(dá)視圖之前,會(huì)依次執(zhí)行中間件,視圖返回的響應(yīng),依次倒序執(zhí)行中間件。
在django中,中間件的是一個(gè)個(gè)的類,類中定義了一些方法。在django項(xiàng)目的setting.py文件中,有一個(gè)MIDDLEWARE列表,其中每一個(gè)元素都是一個(gè)中間件。

如果需要對(duì)請(qǐng)求作統(tǒng)一處理,比如在執(zhí)行視圖前,驗(yàn)證登錄,日志記錄,我們可以用裝飾器,但是很麻煩,每個(gè)視圖都要手動(dòng)加裝飾器語(yǔ)法。這時(shí)如果用中間件會(huì)更方便。

中間件的執(zhí)行原理

從上圖我們發(fā)現(xiàn),MIDDLEWARE列表中的每一個(gè)元素都是字符串,那么Django是如何通過(guò)字符信息執(zhí)行的中間件呢。

觀察中間件元素發(fā)現(xiàn)由兩部分構(gòu)成:路徑+類名;因此如果能分離出路徑,并根據(jù)路徑導(dǎo)入模塊,然后執(zhí)行模塊中類的方法,就可以了。

關(guān)鍵問(wèn)題是路徑和類名都是字符串,通過(guò)字符串路徑導(dǎo)入模塊要借助importlib模塊;在模塊中通過(guò)字符串拿到類和在類中根據(jù)字符串拿到方法,都可以通過(guò)反射來(lái)做。

下面我們來(lái)自己模擬一下:

PLUGIN = {'disk': 'plugin.disk.Disk','memory': 'plugin.memory.Memory','network': 'plugin.network.Network', }

這里用了字典的形式,原理是一樣的。

import importlib # 通過(guò)字符串導(dǎo)入模塊for k, v in PLUGIN.items():# 分離模塊路徑 和 類名:# 'plugin.disk.Disk' --> 模塊路徑'plugin.disk' 類名 'Disk' (結(jié)果都是字符串)# 通過(guò)字符串路徑導(dǎo)入模塊 importlib# 通過(guò)反射獲取模塊中的類module_name, cls_name = v.rsplit('.', maxsplit=1)module = importlib.import_module(module_name)cls = getattr(module, cls_name)obj = cls() # 實(shí)例化對(duì)象res = obj.method() # 調(diào)用對(duì)象的綁定方法

自定義中間件

下面我們自定義一個(gè)中間件,用于用戶驗(yàn)證:

from django.utils.deprecation import MiddlewareMixin # 導(dǎo)入類class M1(MiddlewareMixin): # 自定義類,繼承MiddlewareMixindef process_request(self, request):print('--- 自定義中間件進(jìn)行登錄驗(yàn)證 ---')# 如果訪問(wèn)路徑是login函數(shù),放行;否則驗(yàn)證session信息if request.path_info == 'login.html':return Nonefrom django.shortcuts import redirectif not request.session.get('user_info'):return redirect('/login.html')def process_response(self, request, response):print('自定義邏輯')return response

注意,新版django可能無(wú)法導(dǎo)入,因此,直接把MiddlewareMixin類拿過(guò)來(lái)繼承就好了:

class MiddlewareMixin(object):def __init__(self, get_response=None):self.get_response = get_responsesuper(MiddlewareMixin, self).__init__()def __call__(self, request):response = Noneif hasattr(self, 'process_request'):response = self.process_request(request)if not response:response = self.get_response(request)if hasattr(self, 'process_response'):response = self.process_response(request, response)return responseclass M1(MiddlewareMixin): # 自定義類,繼承MiddlewareMixin......

注意,自定義類時(shí),類中的方法和參數(shù)都是固定的。
定義完成后,在setting.py中找到MIDDLEWARE列表,將我們剛剛自定義的中間件路徑添加進(jìn)去:

這樣,每次請(qǐng)求進(jìn)來(lái),都會(huì)先執(zhí)行自定義的中間件。

中間件中的方法

  • process_request 請(qǐng)求進(jìn)來(lái)時(shí)執(zhí)行;不能有返回值,一旦某個(gè)中間件的process_request 有返回值,那么下面的中間件就不走了,后面的url路由,視圖函數(shù)更不會(huì)執(zhí)行,直接執(zhí)行當(dāng)前中間件的process_response方法,層層往上返回這個(gè)返回值(如果process_response返回了其它值,或者上面的中間件返回了其它值,最后執(zhí)行的返回值會(huì)覆蓋之前的返回值。
class M1(MiddlewareMixin):def process_request(self, request, response):from django.shortcuts import HttpResponseallowed_ip = ['192.168.0.11',]# 維護(hù)一個(gè)允許/禁止訪問(wèn)的ip地址列表,判斷請(qǐng)求ip, 放行/阻攔if request.META.get('REMOTE_ADDR') not in allowed_ip:return HttpResponse('請(qǐng)回去吧')else:return Nonedef process_response(self, request, response):return response
  • process_response 返回響應(yīng)時(shí)執(zhí)行,默認(rèn)情況下返回response, 即視圖函數(shù)的返回值,如果在這個(gè)方法中自定義了返回值,將返回自定義返回值。
class M1(MiddlewareMixin):def process_response(self, request, response):print('自定義邏輯')return response
  • process_view
class M1(MiddlewareMixin):def process_view(self, request, view_func, view_func_args, view_func_kwargs):print('M2.process_view')

執(zhí)行時(shí)機(jī):執(zhí)行完process_request – > 路由分發(fā), – > process_view –> 視圖函數(shù) –> process_response。process_view一旦有返回值,那么跳過(guò)下面的中間件,開始從視圖層層往上,返回響應(yīng)。假設(shè)有多個(gè)中間件,每個(gè)中間件中都定義了以上三個(gè)方法,那么django執(zhí)行中間件的邏輯其實(shí)相當(dāng)于將每個(gè)中間件中的一類方法放到一個(gè)列表里,一共3個(gè)列表,循環(huán)列表執(zhí)行其中的方法,過(guò)程如下:

for process_request in process_request_list:process_request()執(zhí)行路由分發(fā) urlfor process_view in process_view_list:process_view()執(zhí)行視圖 func()for process_response in process_response_list:process_response()
  • process_exception 默認(rèn)不執(zhí)行;如果視圖中出現(xiàn)異常,就會(huì)被執(zhí)行。應(yīng)用場(chǎng)景:自定義一個(gè)”更友好“的錯(cuò)誤頁(yè)面;
class M2(MiddlewareMixin):def process_exception(self, request, exception):from django.shortcuts import HttpResponsereturn HttpResponse('開發(fā)該功能的程序員已被關(guān)小黑屋')
  • process_template_response 默認(rèn)不執(zhí)行;如果返回的對(duì)象有render方法,就會(huì)被執(zhí)行。不常用。
class MyResponse(object): # 我們可以在自定義類中對(duì)響應(yīng)作進(jìn)一步處理def __init__(self, response):self.response = responsedef render(self):return self.responsedef demo(request):response = HttpResponse('OK')return MyResponse(response) # 將響應(yīng)作為字定類的的對(duì)象返回,擁有render方法

總結(jié)

以上是生活随笔為你收集整理的Django(五)中间件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。