[Python自學] day-22 (1) (Session、CSRF、中間件)

1、響應函數補充

三種返回響應的方式:html

return HttpResponse()
return render()
return redirect()

HttpResponse:python

除了可以返回字符串,還能返回bytes。jquery

content = "Hello"
return HttpResponse(content)
return HttpResponse(bytes(content))

render:ajax

返回渲染後的模板。redis

return render(request, 'mlogin.html', {"pwd_error": pwd_error_msg})

redirect:數據庫

跳轉到url。django

return redirect('/mgmt/host')

三種方式均可以設置cookie:後端

response = redirect(...)  # 或HttpResponse、render
response.set_cookie('key', 'value')

set_cookie是將cookie放在響應頭中的。瀏覽器

 

2、Session介紹

因爲Cookie存放在客戶端瀏覽器,因此Cookie是不安全的,能夠被人查看和修改,甚至僞造緩存

Cookie不適合存放敏感信息,例如密碼等。

因此,咱們能夠將本來存放在Cookie中的數據,放置到服務器端,例如:

{
    'username':'Alex',
    'id':'12973',
    'favor':'xxxxxx'
}

而後,服務器在保存這些數據以前,生成一個隨機字符串。並將這個字符串使用set_cookie放置在客戶端。並在服務器也保存一份,做爲數據的key,例如:

session = {
    # 某用戶的session
    'h9j2j3987d2bksjf98': {
        'username': 'Alex',
        'id': '12973',
        'is_login':True,  
        'favor': 'xxxxxx'
    },
    # 另外一個用戶的session
    'h978hnjdfi9100':{
        'username': 'Leo',
        'id': '12989',
        'is_login':True,  
        'favor': 'yyyyyy'
    }
}

客戶端瀏覽器保存的cookie爲:

sessionid = 'h9j2j3987d2bksjf98'

當用戶請求時,攜帶該sessionid。服務器拿到這個隨機ID後,會到session中查到對應的數據(例如is_login),若是is_login爲True,則說明用戶登陸過。

優勢:一樣完成了用戶驗證,並且數據存放在服務端,安全性更高。

缺點:增長了服務器開銷。

 

3、Session使用

1.使用Session前建立數據庫

python manage.py makemigrations
python manage.py migrate

2.查看session表

 

Django的Session默認是放在數據庫的django_session表中的。

3.在視圖函數中使用session

def login(request):
    # 若是是get請求,則檢查session中is_login是否爲True,若是有則免登陸,沒有則跳轉到登陸界面
    if request.method == 'GET':
        if request.session.get('is_login'):
            return redirect('/index')
        else:
            return render(request, 'login.html')
    # 若是是post請求,則獲取請求數據,並驗證用戶名密碼。
    if request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        # 若是驗證經過,則寫session,寫入username和is_login,並跳轉到業務頁面index
        if user == USER_DICT.get('username') and pwd == USER_DICT.get('password'):
            request.session['username'] = user
            request.session['is_login'] = True
            return redirect('/index')
        else:
            # 沒驗證經過,則跳轉回login頁面
            return redirect('/login')

4.django處理session原理

1)當咱們使用request.session['is_login']=True設置session時,django會自動生成隨機字符串(set_cookie以及本身保留一份存數據庫)

2)存放session的鍵值對到數據庫中(如今不少可能使用的是NOSQL數據庫,例如redis之類,而且session要提供共享功能,方便網站分佈式部署)

3)當瀏覽器帶着sessionid請求時(以下圖),視圖函數中使用request.session['is_login']獲取值時,django會使用sessionid,去數據庫中查詢對應條目的is_login(以下圖)

 

不少網站不必定使用Django框架,因此在請求頭中不必定能看到sessionid,但通常都有一個對應的ID來表示用戶:

 

 這是博客園存放的已登陸用戶的隨機字符串,相似於sessionid。後臺拿到這個id後,能夠從數據庫中獲取用戶信息。

 

4、session操做

Django爲session提供了不少操做。

1.普通鍵值操做

# 相似字典操做session
request.session['k1'] = 123  # 設置k1的值
k1 = request.session['k1']  # 取k1的值,若是k1不存在,則報錯
k1 = request.session.get('k1', None)  # 取k1的值,不存在則返回None
del request.session['k1']  # 刪除k1及對應的值

2.鍵值批量操做

request.session.keys()  # 獲取全部key列表
request.session.values()  # 獲取全部value
request.session.items()  # 獲取全部鍵值對
request.session.iterkeys()  # 返回全部key迭代器
request.session.itervalues()  # 返回全部value迭代器
request.session.iteritems()  # 返回全部item迭代器

3.session刪除操做

# 清空數據庫中過時的session
request.session.clear_expired()
# 獲取用戶對應隨機字符串(cookie中的sessionid)
sk = request.session.session_key
# 判斷隨機字符串在數據庫是否存在(通常用不到,由於在獲取session某個值得時候底層也會進行這個操做)
request.session.exists(sk)
# 刪除當前用戶的全部Session數據
request.session.delete(sk)
#
request.session.clear()  # 通常在用戶註銷時使用

 

4.session過時時間

爲session設置過時時間:

request.session.set_expiry(10)  #單位是秒

當這樣設置之後,全部session的過時時間都是10秒。若是不設置的話,Session的過時時間默認是兩週。

設置瀏覽器關閉時過時:

request.session.set_expiry(0)  #設置爲0時,瀏覽器關閉過時

在這種狀況下,瀏覽器的sessionid cookie沒有設置過時時間,因此關閉瀏覽器,Cookie就消失了, 天然沒法再利用session來認證。可是在後臺數據庫中還存在sessionid的記錄

 

5、session配置

1.Session默認配置:

先查看一下Django對Session的默認配置:

from django.conf import settings

print(settings.SESSION_COOKIE_NAME)   # 'sessionid'
print(settings.SESSION_COOKIE_PATH)  #'/'
print(settings.SESSION_COOKIE_DOMAIN)  # None
print(settings.SESSION_COOKIE_SECURE)  # False
print(settings.SESSION_COOKIE_HTTPONLY)  # True
print(settings.SESSION_COOKIE_AGE)  #1209600
print(settings.SESSION_EXPIRE_AT_BROWSER_CLOSE)  # False
print(settings.SESSION_SAVE_EVERY_REQUEST)  # False

以上打印的值即爲默認值。

要修改session的默認配置,只需在settings.py配置文件中修改:

SESSION_COOKIE_NAME = "sessionid"  # session產生的隨機字符串保存到瀏覽器cookie時的名字,默認就是sessionid
SESSION_COOKIE_PATH = "/"  # Session的cookie生效路徑
SESSION_COOKIE_DOMAIN = None  # Session的cookie生效域名
SESSION_COOKIE_SECURE = False  # 是否Https傳輸cookie
SESSION_COOKIE_HTTPONLY = True  # 是否只支持http傳輸
SESSION_COOKIE_AGE = 1209600  # 默認兩週失效
SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否關閉瀏覽器使得Session過時
SESSION_SAVE_EVERY_REQUEST = False  # 是否每次請求都保存Session,即失效時間根據每次請求向後推

以上配置直接寫在setting中便可。

 

2.Session配置後端存儲

數據庫後端:(默認)

# settings.py

SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默認)

緩存後端:

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

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '192.168.1.3:11211',
            '192.168.1.4:11211',
        ]
    },
}

文件後端:

SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
#SESSION_FILE_PATH = None                                    # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir()SESSION_FILE_PATH = os.path.join(BASE_DIR,'cache')     # 在工程目錄下建立一個cache目錄來存放session

 

緩存+數據庫做爲後端:(推薦)

數據庫作持久化,緩存提升效率。前提是緩存和數據庫都要配置好,參照前面分別的配置。

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

加密cookie session:(不推薦)

將session的數據所有加密後放在cookie中,這種方式不能算一種後端存儲技術,實際上都是cookie了。

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

 

總結:以上幾種Session配置只是使用的引擎不一樣,使用方法都是同樣的。前面的默認配置就是通用配置。

 

Redis做爲Session存儲(推薦): 

第一種配置方法:

首先安裝django-redis-sessions:

pip install django-redis-sessions
# settings中配置
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS = {
    'host': '192.168.1.181',
    'port': 6379,
    'db': 2,  # 哪一個數據庫
    'password': '',
    'prefix': 'session',  # key的前綴
    'socket_timeout': 10
    }

能夠看到在redis中,session存儲爲如下形式:

127.0.0.1:6379[2]> keys *
1) "session:fnifus1tqkbilhr1k549mcn5q9k5utdv"

形式爲,prefix:session_id。

 

第二種配置方法:

首先安裝django_redis:

pip install django_redis
# 在settings中配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        # 把這裏緩存你的redis服務器ip和port
        "LOCATION": "redis://192.168.1.181:6379/3",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}


# 咱們定義一個cache(本地緩存來存儲信息,cahe指定的是redis
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
# 指定本地的session使用的本地緩存名稱是'default'
SESSION_CACHE_ALIAS = "default"

這種配置方式下,session存儲爲如下形式:

127.0.0.1:6379[3]> keys *
1) ":1:django.contrib.sessions.cachefj33bv40gk7gf2srklfi2fminmohnskb"

 

6、CSRF

在前面的章節,咱們註釋掉了CSRF中間件,由於發送post請求的時候出現403錯誤。

1.CSRF原理

CSRF是用來防止有人在其餘非法站點向咱們的某個頁面發送POST請求。

CSRF啓用的時候,咱們以GET方式請求一個頁面時,Django會生成隨機字符串(分別放在render的參數中,以及cookie中,兩個字符串是獨立的),並傳遞到頁面。

在咱們提交表單時,必須攜帶該隨機字符串,才能正常提交,不然報403forbid錯誤。

 

因爲咱們提交數據可使用form表單,也可使用Ajax,因此對應兩個地方須要獲取隨機字符串。

在settings.py中啓用CSRF中間件:

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',
]

 

2.Form表單提交時使用CSRF

<body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user"/>
        <input type="password" name="pwd"/>
        <input type="submit" value="提交"/>
    </form>
</body>

咱們使用了{%csrf_token%}後,在頁面元素中能夠看到:

 

 

Django爲咱們自動添加了一個隱藏的<input>標籤,value就是csrf隨機字符串。後臺能夠自動獲取這個值並驗證。

 

3.在Ajax提交Post請求時使用CSRF

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user"/>
        <input type="password" name="pwd"/>
        <input type="submit" value="提交"/>
        <input id='ajax_btn' type="button" value="Ajax提交"/>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        $(function () {
            $('#ajax_btn').click(function(){
                $.ajax({
                    url:'/login',
                    type:'POST',
                    data:{'user':'leokale','pwd':123},
                    headers:{'X-CSRFtoken':$.cookie('csrftoken')},
                    success:function(arg){
                        location.reload()
                    }
                })
            })
        })
    </script>
</body>
</html>

以上這種使用方法在有不少Ajax提交的時候顯得不是很方便,由於要爲每個Ajax的請求添加 X-CSRFtoken字段,因此可使用如下方式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <input type="text" name="user"/>
        <input type="password" name="pwd"/>
        <input type="submit" value="提交"/>
        <input id='ajax_btn' type="button" value="Ajax提交"/>
        <input id='ajax_btn2' type="button" value="Ajax提交2"/>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script src="/static/jquery.cookie.js"></script>
    <script>
        $(function () {
            //在這裏的配置,對全部該頁面的Ajax都生效
 $.ajaxSetup({ beforeSend: function(xhr,settings){ xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken')); } }); //在ajaxSetup中配置後,ajax中就不用再設置X-CSRFtoken了
            $('#ajax_btn').click(function(){
                $.ajax({
                    url:'/login',
                    type:'POST',
                    data:{'user':'leokale','pwd':123},
                    success:function(arg){
                        location.reload()
                    }
                })
            });
            $('#ajax_btn2').click(function(){
                $.ajax({
                    url:'/login',
                    type:'POST',
                    data:{'user':'leokale','pwd':123},
                    success:function(arg){
                        location.reload()
                    }
                })
            });
        })
    </script>
</body>
</html>

在ajaxSetup中能夠進行ajax的全局配置,後面的全部ajax操做都不用單獨添加csrf值了。

 

在ajaxSetup中,參數xhr表示xmlHttpRequest,settings參數表示從後面$.ajax函數參數中得到的字典:

因此咱們應該在ajaxSetup中對請求方法進行過濾,GET|HEAD|OPTIONS|TRACE 請求不添加csrf字符串,其他請求類型才添加:

//使用正則判斷是不是GET|HEAD|OPTIONS|TRACE
function csrfSafeMethod(method){
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
//在這裏的配置,對全部該頁面的Ajax都生效
$.ajaxSetup({
    beforeSend: function(xhr,settings){
        // 若是不是GET|HEAD|OPTIONS|TRACE,就在請求頭中添加x-csrftoken
        if(!csrfSafeMethod(settings.type)){
            xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'));
        }
    }
});

 

4.兩個CSRF token

特別注意,在ajax中爲請求頭添加xsrf隨機字符串,這個字符串是從cookie中得到的。當咱們第一次以GET請求login頁面時,Django除了使用render傳遞了一個csrftoken,還在cookie中放置了一個csrftoken:

 

 

對比經過{%csrf_token%}拿到的字符串:

 

 

能夠發現這兩個字符串是不同的,因此這兩種方式的CSRF token是分別驗證的。

 

7、按需使用CSRF

在settings.py中啓用CSRF中間件,至關於全部的views.py視圖方法或類中都要驗證CSRF隨機字符串。可是有時候這樣是不合適的。

經過裝飾器,按照需求來爲視圖函數添加CSRF驗證:

from django.views.decorators.csrf import csrf_exempt, csrf_protect


@csrf_protect def login(request):
    return HttpResponse("login page")


@csrf_protect def index(request):
    return HttpResponse("login page")


def host(request):
    return HttpResponse("login page")

當settings.py中的csrf配置爲禁用時(對所有視圖函數禁用csrf驗證),上述代碼表示login()和index()啓用csrf驗證。

from django.views.decorators.csrf import csrf_exempt, csrf_protect


def login(request):
    return HttpResponse("login page")


def index(request):
    return HttpResponse("login page")


@csrf_exempt def host(request):
    return HttpResponse("login page")

當settings.py中的csrf配置爲啓用時(對所有視圖函數啓用csrf驗證),上述代碼表示host()禁用csrf驗證。

 

8、Middle Ware中間件

1.Django的中間件是什麼

當用戶發一個請求時,請求到達Django框架後,這個請求要通過一系列的中間件才能到達視圖函數。

咱們能夠在settings.py中查看通過了哪些中間件:

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',
]

以上列表中,每一條表明一個類,每一個類都是一箇中間件,咱們的請求會從上到下一個一個通過,才能到達視圖函數進行處理。

視圖函數處理完畢後,使用HttpResponse、render、redirect返回響應時,又要從下到上通過全部的中間件,最終才能返回給瀏覽器。

 

2.中間件如何工做

如圖,每一箇中間件都有兩個方法,一個處理request,另外一個處理response:

 

咱們查看Django提供的中間件源碼,能夠看到如下代碼:

class SessionMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
        #......

    def process_request(self, request):
        #......

    def process_response(self, request, response):
        # ......
        return response

中間件類繼承於類MiddlewareMixin,一樣咱們看如下它的源碼:

class MiddlewareMixin:
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        response = response or self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

咱們仿照SessionMiddleware,就能夠實現本身的中間件。

 

3.實現本身的中間件

建立mymiddles文件夾,在其中建立mm1.py:

from django.utils.deprecation import MiddlewareMixin


# 定義第一個中間件
class MyMiddle1(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle1, process request, Done')

    def process_response(self, request, response):
        print('This is MyMiddle1, process response, Done')
        return response


# 定義第二個中間件
class MyMiddle2(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle2, process request, Done')

    def process_response(self, request, response):
        print('This is MyMiddle2, process response, Done')
        return response


# 定義第三個中間件
class MyMiddle3(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle3, process request, Done')

    def process_response(self, request, response):
        print('This is MyMiddle3, process response, Done')
        return response

咱們定義了三個中間件。

修改settings.py配置文件,在中間件列表中加入咱們本身的中間件:

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',
    'mymiddles.mm1.MyMiddle1', 'mymiddles.mm1.MyMiddle2', 'mymiddles.mm1.MyMiddle3',
]

 

4.測試中間件

咱們任意發一個請求,在後臺獲得如下打印信息:

This is MyMiddle1, process request, Done
This is MyMiddle2, process request, Done
This is MyMiddle3, process request, Done
This is MyMiddle3, process response, Done
This is MyMiddle2, process response, Done
This is MyMiddle1, process response, Done
[23/Dec/2019 21:42:44] "GET /login HTTP/1.1" 200 2115

咱們能夠看到,request按照流程圖中所示,前後通過 MyMiddle1 ---> MyMiddle2  ---> MyMiddle3 

response前後通過 MyMiddle3 ---> MyMiddle2  ---> MyMiddle1

 

5.中間件的做用

既然request和response都要通過中間件(特別是request),咱們就能夠在中間件中對request進行一些規則過濾、檢查等。

當某個中間件驗證不經過,則request不能到達下一層中間件,直接返回,例如:

# 定義第二個中間件
class MyMiddle2(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle2, process request, Done')
        if request.headers.get('Host') == '127.0.0.1:8000': return HttpResponse("走開") def process_response(self, request, response):
        print('This is MyMiddle2, process response, Done')
        return response

咱們在第二個中間件中添加一個過濾條件,當請求恰好知足這條時,直接返回HttpResponse。後臺能夠看到如下打印信息:

[23/Dec/2019 21:51:00] "GET /login HTTP/1.1" 200 6
This is MyMiddle1, process request, Done
This is MyMiddle2, process request, Done
This is MyMiddle2, process response, Done
This is MyMiddle1, process response, Done

咱們發現第二個中間件並無將request交給後面的中間件。

 

總結:經過中間件,咱們能夠對請求和響應進行自定義的過濾。

 

6.中間件中的process_view方法

除了前面所描述的process_request和process_response方法,中間件還有process_view方法。如圖:

 

 

當request進過了每一層中間件的process_request方法後,會通過urls.py路由系統,找到對應的視圖函數。

而後折返到第一層中間件執行process_view方法:

from django.utils.deprecation import MiddlewareMixin


# 定義第一個中間件
class MyMiddle1(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle1, process request, Done')

    def process_response(self, request, response):
        print('This is MyMiddle1, process response, Done')
        return response

    # view_func就是對應的視圖函數,view_func_args對應視圖函數的*args參數,view_func_kwargs對應**kwargs參數
    def process_view(self, request, view_func, view_func_args, view_func_kwargs):
        print('This is MyMiddle1, process view, Done')


# 定義第二個中間件
class MyMiddle2(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle2, process request, Done')

    def process_response(self, request, response):
        print('This is MyMiddle2, process response, Done')
        return response

    # view_func就是對應的視圖函數,view_func_args對應視圖函數的*args參數,view_func_kwargs對應**kwargs參數
    def process_view(self, request, view_func, view_func_args, view_func_kwargs):
        print('This is MyMiddle2, process view, Done')


# 定義第三個中間件
class MyMiddle3(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle3, process request, Done')

    def process_response(self, request, response):
        print('This is MyMiddle3, process response, Done')
        return response

    # view_func就是對應的視圖函數,view_func_args對應視圖函數的*args參數,view_func_kwargs對應**kwargs參數
    def process_view(self, request, view_func, view_func_args, view_func_kwargs):
        print('This is MyMiddle3, process view, Done')

測試結果打印以下:

This is MyMiddle1, process request, Done
This is MyMiddle2, process request, Done
This is MyMiddle3, process request, Done
This is MyMiddle1, process view, Done
This is MyMiddle2, process view, Done
This is MyMiddle3, process view, Done
執行了login()
This is MyMiddle3, process response, Done
This is MyMiddle2, process response, Done
This is MyMiddle1, process response, Done

能夠看到,request先通過process_request,而後折返通過process_view,而後執行視圖函數,再經過process_response返回數據。

 

7.中間件中的process_exception方法

中間件中還有一個叫process_exception的方法,這個方法主要用來處理視圖函數中的異常。處理流程圖:

咱們在視圖函數中添加一個錯誤:

def login(request):
    int('asdf') #......

而後在三個中間件中添加process_exception方法:

def process_exception(self,request,exception):
    print(exception)  # 打印視圖函數中出現的異常
    return HttpResponse("出現異常")

當視圖函數出現異常時,他會將異常交給離他最近的中間件(有process_exception的),例如MyMiddle3。

若是這個中間件對異常進行了處理(如上代碼中return HttpResponse('出現異常')),則頁面顯示「出現異常」。

不然,會繼續交給下一個中間件的process_exception方法(例如MyMiddle2),若是全部的中間件都沒有處理這個異常,則頁面報錯。

 

8.中間件中的process_template_response方法

這個方法主要用來讓用戶自定義render方法。例如咱們修改視圖函數:

class Foo(object):
    def render(self):
        return HttpResponse('自定義render')


# 視圖函數login
def login(request):
    return Foo()

咱們本身定義了一個類Foo,具備成員方法render(必須這個名字)。而後讓視圖函數返回Foo的一個對象。

而後在中間件中實現process_template_response方法:

# 定義第一個中間件
class MyMiddle1(MiddlewareMixin):
    def process_request(self, request):
        print('This is MyMiddle1, process request, Done')

    def process_response(self, request, response):
        print('This is MyMiddle1, process response, Done')
        return response

    # view_func就是對應的視圖函數,view_func_args對應視圖函數的*args參數,view_func_kwargs對應**kwargs參數
    def process_view(self, request, view_func, view_func_args, view_func_kwargs):
        print('This is MyMiddle1, process view, Done')

    def process_template_response(self,request,response): print('This is MyMiddle1, process template response, Done') return response

這樣,process_template_response方法就會執行,咱們將Foo對象直接返回,Django會將該對象裏render函數的返回值做爲數據返回給瀏覽器。咱們在頁面上能夠看到:

 

因此,process_template_response方法,主要就是讓咱們自定義模板渲染方法。可是通常沒怎麼用。

相關文章
相關標籤/搜索