django框架之中間件

內容回顧:html

  內容回顧:https://www.cnblogs.com/liwenzhou/p/8343243.html
    1. Cookie和Session
        1. Cookie是什麼?
            保存在瀏覽器端的鍵值對
        2. 爲何要有Cookie?
            Http請求是無狀態,服務端在返回響應的時候讓瀏覽器記錄的鍵值對
        3. Django中如何使用Cookie
            1. 設置Cookie
                rep = redirect('/home/')
                rep.set_cookie(key, value, max_age=60*60*24*7)          --> 設置明文Cookie,有效期是7天
                
                rep.set_signed_cookie(key, value, salt="", max_age=10)  --> 設置加鹽的Cookie,有效期是10秒
            2. 獲取Cookie
                request.COOKIES    --> 獲取請求中的Cookie數據,數據格式是大字典
                    request.COOKIES[key]                不推薦這種寫法
                    request.COOKIES.get(key, "默認值")  推薦使用這種方法取值
                request.GET        --> 獲取URL裏面的參數
                request.POST       --> 獲取POST請求的參數
                request.FILES      --> 上傳文件的數據
                
                request.get_signed_cookie(key, default="默認值", salt="")   --> 獲取加鹽的Cookie
                
            3. 刪除Cookie(用於註銷)
                rep = redirect('/home/')
                rep.delete_cookie("key")
                
    2. Session
        1. Session是什麼?
            保存在服務器端的鍵值對,依賴於Cookie
            
        2. 爲何要有Session?
            Cookie將數據保存在客戶端(瀏覽器)上,數據不安全。
            Cookie存儲的數據有限制
            
        3. Django中Session操做
            1. 設置Session
                1. request.session[key] = value
                2. request.session.setdefault(key, value)   --> 有就啥都不幹,沒有就賦值
            2. 獲取Session
                1. request.session[key]
                2. request.session.get(key)  推薦
            3. 刪除Session
                1. request.session.delete()
                2. request.session.flush()     --> 刪除Cookie和Session
            4. 清空已通過期的session數據
                request.session.clear_expired()
            5. 設置Session過時時間
                request.session.set_expiry(過時時間)
                
        4. Django中Session的配置項
            1. 配置寫在settings.py中
            2. 幾個經常使用的配置項
                1. 全局設置Session的過時時間
                    SESSION_COOKIE_AGE = 1209600        --> 默認兩週
                2. 設置每次請求來都刷新過時時間
                    SESSION_SAVE_EVERY_REQUEST = True 數據庫

今日內容:django

什麼是中間價?瀏覽器

    是幫助咱們在視圖函數執行以前和執行以後均可以作一些額外的操做,它本質上就是一個自定義類,類中定義了幾個方法,Django框架會在請求的特定的時間去執行這些方法。安全

咱們一直都在使用中間件,只是沒有注意到而已,打開Django項目的Settings.py文件,看到的MIDDLEWARE配置項。服務器

MIDDLEWARE配置項是一個列表,列表中是一個個字符串,這些字符串實際上是一個個類,也就是一個個中間件。cookie

咱們以前已經接觸過一個csrf相關的中間件了?咱們一開始讓你們把他註釋掉,再提交post請求的時候,就不會被forbidden了,後來學會使用csrf_token以後就再也不註釋這個中間件了。session

自定義中間件:

中間件能夠定義五個方法,分別是:(主要的是process_request和process_response)app

  • process_request(self,request)
  • process_view(self, request, view_func, view_args, view_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

以上方法的返回值能夠是None或一個HttpResponse對象,若是是None,則繼續按照django定義的規則向後繼續執行,若是是HttpResponse對象,則直接將該對象返回給用戶。框架

咱們如今項目目錄下建立一個文件夾來放咱們的中間件文件,而後建立yigepy文件。自定義一箇中間件。每一箇中間件都是一個類。

首先咱們來學習第一種方法:

process_request:

process_request有一個參數,就是request,這個request和視圖函數中的request是同樣的。

它的返回值能夠是None也能夠是HttpResponse對象。返回值是None的話,按正常流程繼續走,交給下一個中間件處理,若是是HttpResponse對象,Django將不執行視圖函數,而將相應對象返回給瀏覽器。

from django.utils.deprecation import MiddlewareMixin

class MD1(MiddlewareMixin):
        def process_request(self,request):
        print(id(request)) #這個request和視圖函數中的request是同樣的。打印id能夠驗證
        request.s12 = ’哈哈哈‘ #也能夠給request對象設置屬性,這個屬性能夠在視圖函數調用。
print(‘這是自定義中間件MD1中的 process_request’)
        return HttpResponse("呵呵") # 若是有return,則Django將不執行視圖函數,而將相應對象返回給瀏覽器。

class MD2(MiddlewareMixin):#定義多箇中間件,
    def process_request(self, request):
      print("
這是自定義中間件MD2中的 process_request")

在settings.py的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',
    'middlewares.MD1',  # 自定義中間件MD1
    'middlewares.MD2'  # 自定義中間件MD2  文件名.類名
]

此時,咱們訪問一個視圖,會發現終端中打印以下內容:

這是自定義中間件MD1中的 process_request
這是自定義中間件MD2中的 process_request
這是視圖函數。。。。

把MD1和MD2的位置調換一下,再訪問一個視圖,會發現終端中打印的內容以下:

這是自定義中間件MD2中的 process_request
這是自定義中間件MD1中的 process_request
這是視圖函數。。。。。

由此總結一下:

  1. 中間件的process_request方法是在執行視圖函數以前執行的。
  2. 當配置多箇中間件時,會按照MIDDLEWARE中的註冊順序,也就是列表的索引值,從前到後依次執行的。
  3. 不一樣中間件之間傳遞的request都是同一個對象

process_response:

它有兩個參數,一個是request,一個是response,request就是上述例子中同樣的對象,response是視圖函數返回的HttpResponse對象。該方法的返回值也必須是HttpResponse對象。

給上述的MD1和MD2加上process_response方法:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class MD1(MiddlewareMixin):  
  def process_request(self,request):
    print(id(request)) #這個request和視圖函數中的request是同樣的。打印id能夠驗證
    request.s12 = ’哈哈哈‘ #也能夠給request對象設置屬性,這個屬性能夠在視圖函數調用。 print(‘這是自定義中間件MD1中的 process_request’)
    return HttpResponse(‘阿瑟東’)
  def process_response(self,reuqest,response)
    print (‘這是自定義中間件MD1中的 process_response’
    return response

class MD2(MiddlewareMixin):#定義多箇中間件,
    def process_request(self, request):
      print("這是自定義中間件MD2中的 process_request")

    def process_response(self,reuqest,response)
      print (‘這是自定義中間件MD2中的 process_response’)
      return response
 

訪問一個視圖,看一下終端的輸出:

 
這是自定義中間件MD1中的 process_request
這是自定義中間件MD2中的 process_request

這是試圖函數。。。。。
這是自定義中間件MD2中的 process_response
這是自定義中間件MD1中的 process_response

看結果可知:

process_response方法是在視圖函數以後執行的,而且順序是MD2比MD1先執行。(此時settings.py中 MD1比MD2先註冊)

多箇中間件中的process_response方法是按照MIDDLEWARE中的註冊順序倒序執行的,也就是說第一個中間件的process_request方法首先執行,而它的process_response方法最後執行,最後一箇中間件的process_request方法最後一個執行,它的process_response方法是最早執行。

 

process_view:

process_view(self, request, view_func, view_args, view_kwargs)

該方法有四個參數

request是HttpRequest對象。

view_func是Django即將使用的視圖函數。 (它是實際的函數對象,而不是函數的名稱做爲字符串。)

view_args是將傳遞給視圖的位置參數的列表.

view_kwargs是將傳遞給視圖的關鍵字參數的字典。 view_args和view_kwargs都不包含第一個視圖參數(request)。

Django會在調用視圖函數以前調用process_view方法。

它應該返回None或一個HttpResponse對象。 若是返回None,Django將繼續處理這個請求,執行任何其餘中間件的process_view方法,而後在執行相應的視圖。 若是它返回一個HttpResponse對象,Django不會調用適當的視圖函數。 它將執行中間件的process_response方法並將應用到該HttpResponse並返回結果。

給MD1和MD2添加process_view方法:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class MD1(MiddlewareMixin):  

  def process_request(self,request):
    print(id(request))   #這個request和視圖函數中的request是同樣的。打印id能夠驗證
    request.s12 = ’哈哈哈‘  #也能夠給request對象設置屬性,這個屬性能夠在視圖函數調用。
       print(‘這是自定義中間件MD1中的 process_request’)
    return HttpResponse(‘阿瑟東’)
  def process_response(self,reuqest,response)
    print (‘這是自定義中間件MD1中的 process_response’)
    return response
  def process_View(self, request, view_func, view_args, view_kwargs):
    """
        對視圖作處理
        :param request: 請求對象
        :param view_func: 要執行的是與函數對象
        :param view_args:
        :param view_kwargs:
        :return:
        """
    # view_func(request) #django會在執行視圖函數以前在執行一遍。
     print(‘這是自定義中間件MD1中的 process_view方法...’)
    # return HttpResponse("嘿嘿嘿")
    
class MD2(MiddlewareMixin):#定義多箇中間件,     def process_request(self, request):       print("這是自定義中間件MD2中的 process_request")     def process_response(self,reuqest,response)       print (‘這是自定義中間件MD2中的 process_response’)       return response
    def process_View(self, request, view_func, view_args, view_kwargs):
    # view_func(request) #django會在執行視圖函數以前在執行一遍。
      print(‘這是自定義中間件MD1中的 process_view方法...’)
    # return HttpResponse("嘿嘿嘿")

訪問index視圖函數,看一下輸出結果:

這是自定義中間件MD1中的 process_request
這是自定義中間件MD2中的 process_response
這是自定義中間件MD1中的 process_view方法...
這是自定義中間件MD1中的 process_view方法...
這是視圖函數。。。。。
這是自定義中間件MD2中的 process_response
這是自定義中間件MD1中的 process_response

process_view方法是在process_request以後,視圖函數以前執行的,執行順序按照MIDDLEWARE中的註冊順序從前到後順序執行的

process_exception:

process_exception(self, request, exception)

該方法兩個參數:

一個HttpRequest對象

一個exception是視圖函數異常產生的Exception對象。

這個方法只有在視圖函數中出現異常了才執行,它返回的值能夠是一個None也能夠是一個HttpResponse對象。若是是HttpResponse對象,Django將調用模板和中間件中的process_response方法,並返回給瀏覽器,不然將默認處理異常。若是返回一個None,則交給下一個中間件的process_exception方法來處理異常。它的執行順序也是按照中間件註冊順序的倒序執行。

給MD1和MD2添加上這個方法:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class MD1(MiddlewareMixin):  

  def process_request(self,request):
    print(id(request))   #這個request和視圖函數中的request是同樣的。打印id能夠驗證
    request.s12 = ’哈哈哈‘  #也能夠給request對象設置屬性,這個屬性能夠在視圖函數調用。
       print(‘這是自定義中間件MD1中的 process_request’)
    return HttpResponse(‘阿瑟東’)
  def process_response(self,reuqest,response)
    print (‘這是自定義中間件MD1中的 process_response’)
    return response
  def process_View(self, request, view_func, view_args, view_kwargs):
    """
        對視圖作處理
        :param request: 請求對象
        :param view_func: 要執行的是與函數對象
        :param view_args:
        :param view_kwargs:
        :return:
        """
    # view_func(request) #django會在執行視圖函數以前在執行一遍。
     print(‘這是自定義中間件MD1中的 process_view方法...’)
    # return HttpResponse("嘿嘿嘿")
     def process_exception(self, request, exception):
            print("這是自定義中間件MD1中的 process_exception 方法...")
            print(exception)
            return HttpResponse("出異常了,我不想讓你看黃色頁面1")
    

class MD2(MiddlewareMixin):#定義多箇中間件,
    def process_request(self, request): 
      print("這是自定義中間件MD2中的 process_request")
    def process_response(self,reuqest,response)
      print (‘這是自定義中間件MD2中的 process_response’)
      return response
    def process_View(self, request, view_func, view_args, view_kwargs):
    #   view_func(request) #django會在執行視圖函數以前在執行一遍。
       print(‘這是自定義中間件MD1中的 process_view方法...’)
    #   return HttpResponse("嘿嘿嘿")     
        def process_exception(self, request, exception):
            print("這是自定義中間件MD1中的 process_exception 方法...")
            print(exception)
            return HttpResponse("出異常了,我不想讓你看黃色頁面1")         

若是視圖函數中無異常,process_exception方法不執行。

想辦法,在視圖函數中拋出一個異常:

 
def index(request):
    print("app01 中的 index視圖")
    raise ValueError("這是一個異常....")
    return HttpResponse("O98K")
 

看輸出結果:

這是自定義中間件ND1中的process——request
這是自定義中間件ND2中的process——request
這是自定義中間件MD1中的 process_view方法...
這是自定義中間件MD2中的 process_view方法...
這是試圖函數
這是自定義中間件MD2中的 process_exception 方法...
這是一個異常...
這是自定義中間件ND2中的process——response
這是自定義中間件ND1中的process——response

注意,這裏並無執行MD1的process_exception方法,由於MD1中的process_exception方法直接返回了一個響應對象。

 

process_template_response(用的比較少):

process_template_response(self, request, response)

它的參數,一個HttpRequest對象,response是TemplateResponse對象(由視圖函數或者中間件產生)。

process_template_response是在視圖函數執行完成後當即執行,可是它有一個前提條件,那就是視圖函數返回的對象有一個render()方法(或者代表該對象是一個TemplateResponse對象或等價方法)。

 
from django .utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):
    def process_request(self,request):
        request.s12='asdf'
        print('這是自定義中間件ND1中的process——request')
    def process_response(self,request,response):

        print('這是自定義中間件ND1中的process——response')
        return response
    def process_view(self,request, view_func, view_args, view_kwargs):
        print('這是自定義中間件MD1中的 process_view方法...')
    def process_exception(self,request,exception):
        print('這是自定義中間件MD1中的 process_exception 方法...')
        print(exception)
        return HttpResponse("出異常了,我不想讓你看黃色頁面1")
    def process_template_response(self,request,response):
        print("這是MD1 中的process_template_response")
        return response


class Md2(MiddlewareMixin):
    def process_request(self,request):
        print('這是自定義中間件ND2中的process——request')

    def process_response(self, request, response):
        print('這是自定義中間件ND2中的process——response')
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('這是自定義中間件MD2中的 process_view方法...')

    def process_exception(self, request, exception):
        print('這是自定義中間件MD2中的 process_exception 方法...')
        print(exception)
        return HttpResponse("出異常了,我不想讓你看黃色頁面1")
    def process_template_response(self,request,response):
        print("這是MD2 中的process_template_response")
        return response
 

views.py中:

from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
    print('這是試圖函數')
    # print(request.s12)
    # raise Exception('這是一個異常...')
    def render():
        print('o98k')
        return HttpResponse('太繞了...')
    rep = HttpResponse('ok')
    rep.render = render
    return rep
    # return HttpResponse('ok')

訪問index視圖,終端輸出的結果:

這是自定義中間件ND1中的process——request
這是自定義中間件ND2中的process——request
這是自定義中間件MD1中的 process_view方法...
這是自定義中間件MD2中的 process_view方法...
這是試圖函數
這是MD2 中的process_template_response
這是MD1 中的process_template_response
o98k
這是自定義中間件ND2中的process——response
這是自定義中間件ND1中的process——response

從結果看出:

視圖函數執行完以後,當即執行了中間件的process_template_response方法,順序是倒序,先執行MD2的,在執行MD1的,接着執行了視圖函數返回的HttpResponse對象的render方法,返回了一個新的HttpResponse對象,接着執行中間件的process_response方法。

 

這就講完了中間件的五種方法,咱們來縷一縷django的執行流程:

django請求完整的生命週期:瀏覽器先發一個請求,先走wsgi,他按照http協議解析一個收發消息,而後走requestMiddles,若是這些中間件都返回none,就繼續日後走,若是返回響應,就走response,而後再url.py文件裏找用戶訪問的路徑,拿到視圖函數後,走viewMiddle中間件,若是仍是都返回none,就執行真正的視圖函數,而後走models.py,往數據庫裏寫數據,拿到數據以後,就能夠去template去渲染頁面了,而後就是生成響應對象了,又經過試圖函數裏的return返回,而後走ResponseMiddles中間件。若是說在視圖函數中有異常,就走exceptionMiddle中間件,而後交給ResponseMiddle。 請求級別的異常處理直接交給ResponseMiddle。

相關文章
相關標籤/搜索