Django----認證系統和auth模塊

COOKIE 與 SESSION

概念

cookie不屬於http協議範圍,因爲http協議沒法保持狀態,但實際狀況,咱們卻又須要「保持狀態」,所以cookie就是在這樣一個場景下誕生。javascript

cookie的工做原理是:由服務器產生內容,瀏覽器收到請求後保存在本地;當瀏覽器再次訪問時,瀏覽器會自動帶上cookie,這樣服務器就能經過cookie的內容來判斷這個是「誰」了。css

cookie雖然在必定程度上解決了「保持狀態」的需求,可是因爲cookie自己最大支持4096字節,以及cookie自己保存在客戶端,可能被攔截或竊取,所以就須要有一種新的東西,它能支持更多的字節,而且他保存在服務器,有較高的安全性。這就是session。html

問題來了,基於http協議的無狀態特徵,服務器根本就不知道訪問者是「誰」。那麼上述的cookie就起到橋接的做用。java

咱們能夠給每一個客戶端的cookie分配一個惟一的id,這樣用戶在訪問時,經過cookie,服務器就知道來的人是「誰」。而後咱們再根據不一樣的cookie的id,在服務器上保存一段時間的私密資料,如「帳號密碼」等等。python

總結而言:cookie彌補了http無狀態的不足,讓服務器知道來的人是「誰」;可是cookie以文本的形式保存在本地,自身安全性較差;因此咱們就經過cookie識別不一樣的用戶,對應的在session裏保存私密的信息以及超過4096字節的文本。jquery

另外,上述所說的cookie和session實際上是共通性的東西,不限於語言和框架算法

登錄應用

前幾節的介紹中咱們已經有能力製做一個登錄頁面,在驗證了用戶名和密碼的正確性後跳轉到後臺的頁面。可是測試後也發現,若是繞過登錄頁面。直接輸入後臺的url地址也能夠直接訪問的。這個顯然是不合理的。其實咱們缺失的就是cookie和session配合的驗證。有了這個驗證過程,咱們就能夠實現和其餘網站同樣必須登陸才能進入後臺頁面了。數據庫

      先說一下這種認證的機制。每當咱們使用一款瀏覽器訪問一個登錄頁面的時候,一旦咱們經過了認證。服務器端就會發送一組隨機惟一的字符串(假設是123abc)到瀏覽器端,這個被存儲在瀏覽端的東西就叫cookie。而服務器端也會本身存儲一下用戶當前的狀態,好比login=true,username=hahaha之類的用戶信息。可是這種存儲是以字典形式存儲的,字典的惟一key就是剛纔發給用戶的惟一的cookie值。那麼若是在服務器端查看session信息的話,理論上就會看到以下樣子的字典django

{'123abc':{'login':true,'username:hahaha'}}bootstrap

由於每一個cookie都是惟一的,因此咱們在電腦上換個瀏覽器再登錄同一個網站也須要再次驗證。那麼爲何說咱們只是理論上看到這樣子的字典呢?由於處於安全性的考慮,其實對於上面那個大字典不光key值123abc是被加密的,value值{'login':true,'username:hahaha'}在服務器端也是同樣被加密的。因此咱們服務器上就算打開session信息看到的也是相似與如下樣子的東西

{'123abc':dasdasdasd1231231da1231231}

知道了原理,下面就來用代碼實現。

Django實現的COOKIE

一、獲取Cookie

1
2
3
4
5
6
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    #參數:
        default: 默認值
           salt: 加密鹽
        max_age: 後臺控制過時時間

二、設置Cookie

1
2
3
4
rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect()
 
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密鹽',...) 

 參數:

複製代碼
'''

def set_cookie(self, key,                 鍵
             value='',            值
             max_age=None,        超長時間
             expires=None,        超長時間
             path='/',           Cookie生效的路徑,
                                         瀏覽器只會把cookie回傳給帶有該路徑的頁面,這樣能夠避免將
                                         cookie傳給站點中的其餘的應用。
                                         / 表示根路徑,特殊的:根路徑的cookie能夠被任何url的頁面訪問
             
                     domain=None,         Cookie生效的域名
                                        
                                          你可用這個參數來構造一個跨站cookie。
                                          如, domain=".example.com"
                                          所構造的cookie對下面這些站點都是可讀的:
                                          www.example.com 、 www2.example.com 
                         和an.other.sub.domain.example.com 。 若是該參數設置爲 None ,cookie只能由設置它的站點讀取。              secure=False, 若是設置爲 True ,瀏覽器將經過HTTPS來回傳cookie。              httponly=False 只能http協議傳輸,沒法被JavaScript獲取 (不是絕對,底層抓包能夠獲取到也能夠被覆蓋)           ): pass '''
複製代碼

因爲cookie保存在客戶端的電腦上,因此,JavaScript和jquery也能夠操做cookie。

1
2
3
<script src='/static/js/jquery.cookie.js'>
 
</script> $.cookie("key", value,{ path: '/'  });

3 刪除cookie

1
response.delete_cookie("cookie_key",path="/",domain=name)

 cookie存儲到客戶端
       優勢:
           數據存在在客戶端,減輕服務器端的壓力,提升網站的性能。
       缺點:
           安全性不高:在客戶端機很容易被查看或破解用戶會話信息

Django實現的SESSION

一、 基本操做

1
2
3
4
5
6
7
8
1、設置Sessions值
          request.session['session_name'="admin"
2、獲取Sessions值
          session_name = request.session["session_name"]
3、刪除Sessions值
          del request.session["session_name"]
4、檢測是否操做session值
          if "session_name" is request.session :
1、設置Sessions值
          request.session['session_name'] ="admin"
2、獲取Sessions值
          session_name = request.session["session_name"]
3、刪除Sessions值
          del request.session["session_name"]
4、檢測是否操做session值
          if "session_name" is request.session :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
五、get(key, default=None)
 
fav_color = request.session.get('fav_color', 'red')
 
6、pop(key)
 
fav_color = request.session.pop('fav_color')
 
7、keys()
 
8、items()
 
9、setdefault()
 
10、flush() 刪除當前的會話數據並刪除會話的Cookie。
            這用於確保前面的會話數據不能夠再次被用戶的瀏覽器訪問
            例如,django.contrib.auth.logout() 函數中就會調用它。
 
 
11 用戶session的隨機字符串
        request.session.session_key
  
        # 將全部Session失效日期小於當前日期的數據刪除
        request.session.clear_expired()
  
        # 檢查 用戶session的隨機字符串 在數據庫中是否
        request.session.exists("session_key")
  
        # 刪除當前用戶的全部Session數據
        request.session.delete("session_key")
  
        request.session.set_expiry(value)
            * 若是value是個整數,session會在些秒數後失效。
            * 若是value是個datatime或timedelta,session就會在這個時間後失效。
            * 若是value是0,用戶關閉瀏覽器session就會失效。
            * 若是value是None,session會依賴全局session失效策略。
View Code

二、 流程解析圖

 三、 示例

views:

def log_in(request):

    if request.method=="POST":
        username=request.POST['user']
        password=request.POST['pwd']

        user=UserInfo.objects.filter(username=username,password=password)

        if user:
            #設置session內部的字典內容
            request.session['is_login']='true'
            request.session['username']=username

            #登陸成功就將url重定向到後臺的url
            return redirect('/backend/')

    #登陸不成功或第一訪問就停留在登陸頁面
    return render(request,'login.html')




def backend(request):
    print(request.session,"------cookie")
    print(request.COOKIES,'-------session')
    """
    這裏必須用讀取字典的get()方法把is_login的value缺省設置爲False,
    當用戶訪問backend這個url先嚐試獲取這個瀏覽器對應的session中的
    is_login的值。若是對方登陸成功的話,在login裏就已經把is_login
    的值修改成了True,反之這個值就是False的
    """

    is_login=request.session.get('is_login',False)
    #若是爲真,就說明用戶是正常登錄的
    if is_login:
        #獲取字典的內容並傳入頁面文件
        cookie_content=request.COOKIES
        session_content=request.session

        username=request.session['username']

        return render(request,'backend.html',locals())
    else:
        """
        若是訪問的時候沒有攜帶正確的session,
        就直接被重定向url回login頁面
        """
        return redirect('/login/')



def log_out(request):
    """
    直接經過request.session['is_login']回去返回的時候,
    若是is_login對應的value值不存在會致使程序異常。因此
    須要作異常處理
    """
    try:
        #刪除is_login對應的value值
        del request.session['is_login']
        
        # OR---->request.session.flush() # 刪除django-session表中的對應一行記錄

    except KeyError:
        pass
    #點擊註銷以後,直接重定向回登陸頁面
    return redirect('/login/')
View Code

template:

===================================login.html==================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="/login/" method="post">
    <p>用戶名: <input type="text" name="user"></p>
    <p>密碼: <input type="password" name="pwd"></p>
    <p><input type="submit"></p>
</form>


</body>
</html>


===================================backend.html==================

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h3>hello {{ username }}</h3>
<a href="/logout/">註銷</a>

</body>
</html>
View Code

四、session存儲的相關配置

(1)數據庫配置(默認):

Django默認支持Session,而且默認是將Session數據存儲在數據庫中,即:django_session 表中。
  
a. 配置 settings.py
  
    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)
      
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串(默認)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路徑(默認)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默認)
    SESSION_COOKIE_SECURE = False                            # 是否Https傳輸cookie(默認)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http傳輸(默認)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默認)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否關閉瀏覽器使得Session過時(默認)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次請求都保存Session,默認修改以後才保存(默認)
View Code

(2)緩存配置 

a. 配置 settings.py
  
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的緩存別名(默認內存緩存,也能夠是memcache),此處別名依賴緩存的設置
  
  
    SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
    SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路徑
    SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                             # 是否Https傳輸cookie
    SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http傳輸
    SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否關閉瀏覽器使得Session過時
    SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次請求都保存Session,默認修改以後才保存
View Code

(3)文件配置

a. 配置 settings.py
  
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 緩存文件路徑,若是爲None,則使用tempfile模塊獲取一個臨時地址tempfile.gettempdir()        
    SESSION_COOKIE_NAME = "sessionid"                          # Session的cookie保存在瀏覽器上時的key,即:sessionid=隨機字符串
    SESSION_COOKIE_PATH = "/"                                  # Session的cookie保存的路徑
    SESSION_COOKIE_DOMAIN = None                                # Session的cookie保存的域名
    SESSION_COOKIE_SECURE = False                               # 是否Https傳輸cookie
    SESSION_COOKIE_HTTPONLY = True                              # 是否Session的cookie只支持http傳輸
    SESSION_COOKIE_AGE = 1209600                                # Session的cookie失效日期(2周)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                     # 是否關閉瀏覽器使得Session過時
    SESSION_SAVE_EVERY_REQUEST = False                          # 是否每次請求都保存Session,默認修改以後才保存
View Code

用戶認證 

auth模塊

1
from  django.contrib  import  auth

django.contrib.auth中提供了許多方法,這裏主要介紹其中的三個:

1 、authenticate()   

提供了用戶認證,即驗證用戶名以及密碼是否正確,通常須要username  password兩個關鍵字參數

若是認證信息有效,會返回一個  User  對象。authenticate()會在User 對象上設置一個屬性標識那種認證後端認證了該用戶,且該信息在後面的登陸過程當中是須要的。當咱們試圖登錄一個從數據庫中直接取出來不通過authenticate()的User對象會報錯的!!

1
user  =  authenticate(username = 'someone' ,password = 'somepassword' )

2 、login(HttpRequest, user)  

該函數接受一個HttpRequest對象,以及一個認證了的User對象

此函數使用django的session框架給某個已認證的用戶附加上session id等信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
from  django.contrib.auth  import  authenticate, login
   
def  my_view(request):
   username  =  request.POST[ 'username' ]
   password  =  request.POST[ 'password' ]
   user  =  authenticate(username = username, password = password)
   if  user  is  not  None :
     login(request, user)
     # Redirect to a success page.
     ...
   else :
     # Return an 'invalid login' error message.
     ...

3 、logout(request) 註銷用戶  

1
2
3
4
5
from  django.contrib.auth  import  logout
   
def  logout_view(request):
   logout(request)
   # Redirect to a success page.

該函數接受一個HttpRequest對象,無返回值。當調用該函數時,當前請求的session信息會所有清除。該用戶即便沒有登陸,使用該函數也不會報錯。

4 、user對象的 is_authenticated()

要求:

1  用戶登錄後才能訪問某些頁面,

2  若是用戶沒有登陸就訪問該頁面的話直接跳到登陸頁面

3  用戶在跳轉的登錄界面中完成登錄後,自動訪問跳轉到以前訪問的地址

方法1:

1
2
3
def  my_view(request):
   if  not  request.user.is_authenticated():
     return  redirect( '%s?next=%s'  %  (settings.LOGIN_URL, request.path))

方法2:

django已經爲咱們設計好了一個用於此種狀況的裝飾器:login_requierd()

1
2
3
4
5
from  django.contrib.auth.decorators  import  login_required
      
@login_required
def  my_view(request):
   ...

若用戶沒有登陸,則會跳轉到django默認的 登陸URL '/accounts/login/ ' (這個值能夠在settings文件中經過LOGIN_URL進行修改)。並傳遞  當前訪問url的絕對路徑 (登錄成功後,會重定向到該路徑)。

User對象

User 對象屬性:username, password(必填項)password用哈希算法保存到數據庫

is_staff : 用戶是否擁有網站的管理權限.

is_active : 是否容許用戶登陸, 設置爲``False``,能夠不用刪除用戶來禁止 用戶登陸

 

2.1 、is_authenticated()

若是是真正的 User 對象,返回值恆爲 True 。 用於檢查用戶是否已經經過了認證。
經過認證並不意味着用戶擁有任何權限,甚至也不檢查該用戶是否處於激活狀態,這只是代表用戶成功的經過了認證。 這個方法很重要, 在後臺用request.user.is_authenticated()判斷用戶是否已經登陸,若是true則能夠向前臺展現request.user.name

2.2 、建立用戶

使用 create_user 輔助函數建立用戶:

1
2
from  django.contrib.auth.models  import  User
user  =  User.objects.create_user(username = ' ',password=' ',email=' ')

2.3 、check_password(passwd)

1
用戶須要修改密碼的時候 首先要讓他輸入原來的密碼 ,若是給定的字符串經過了密碼檢查,返回  True

2.4 、修改密碼

使用 set_password() 來修改密碼

1
2
3
user  =  User.objects.get(username = '')
user.set_password(password = '')
user.save 

2.5 、簡單示例

註冊:

def sign_up(request):
 
    state = None
    if request.method == 'POST':
 
        password = request.POST.get('password', '')
        repeat_password = request.POST.get('repeat_password', '')
        email=request.POST.get('email', '')
        username = request.POST.get('username', '')
        if User.objects.filter(username=username):
                state = 'user_exist'
        else:
                new_user = User.objects.create_user(username=username, password=password,email=email)
                new_user.save()
 
                return redirect('/book/')
    content = {
        'state': state,
        'user': None,
    }
    return render(request, 'sign_up.html', content)  
View Code

修改密碼:

@login_required
def set_password(request):
    user = request.user
    state = None
    if request.method == 'POST':
        old_password = request.POST.get('old_password', '')
        new_password = request.POST.get('new_password', '')
        repeat_password = request.POST.get('repeat_password', '')
        if user.check_password(old_password):
            if not new_password:
                state = 'empty'
            elif new_password != repeat_password:
                state = 'repeat_error'
            else:
                user.set_password(new_password)
                user.save()
                return redirect("/log_in/")
        else:
            state = 'password_error'
    content = {
        'user': user,
        'state': state,
    }
    return render(request, 'set_password.html', content)
View Code

 

Django的分頁器(paginator)

view

複製代碼
from django.shortcuts import render,HttpResponse

# Create your views here.
from app01.models import *
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def index(request):

    '''
    批量導入數據:

    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    Book.objects.bulk_create(Booklist)
    '''

    '''
分頁器的使用:

    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)

    print("count:",paginator.count)           #數據總數
    print("num_pages",paginator.num_pages)    #總頁數
    print("page_range",paginator.page_range)  #頁碼的列表



    page1=paginator.page(1) #第1頁的page對象
    for i in page1:         #遍歷第1頁的全部數據對象
        print(i)

    print(page1.object_list) #第1頁的全部數據


    page2=paginator.page(2)

    print(page2.has_next())            #是否有下一頁
    print(page2.next_page_number())    #下一頁的頁碼
    print(page2.has_previous())        #是否有上一頁
    print(page2.previous_page_number()) #上一頁的頁碼



    # 拋錯
    #page=paginator.page(12)   # error:EmptyPage

    #page=paginator.page("z")   # error:PageNotAnInteger

    '''


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)
    page = request.GET.get('page',1)
    currentPage=int(page)


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})
複製代碼

index.html:

複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" 
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <h4>分頁器</h4> <ul> {% for book in book_list %} <li>{{ book.title }} -----{{ book.price }}</li> {% endfor %} </ul> <ul class="pagination" id="pager"> {% if book_list.has_previous %} <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一頁</a></li> {% else %} <li class="previous disabled"><a href="#">上一頁</a></li> {% endif %} {% for num in paginator.page_range %} {% if num == currentPage %} <li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li> {% else %} <li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li> {% endif %} {% endfor %} {% if book_list.has_next %} <li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一頁</a></li> {% else %} <li class="next disabled"><a href="#">下一頁</a></li> {% endif %} </ul> </div> </body> </html>
複製代碼

擴展

複製代碼
def index(request):


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 15)
    page = request.GET.get('page',1)
    currentPage=int(page)

    #  若是頁數十分多時,換另一種顯示方式
    if paginator.num_pages>30:

        if currentPage-5<1:
            pageRange=range(1,11)
        elif currentPage+5>paginator.num_pages:
            pageRange=range(currentPage-5,paginator.num_pages+1)

        else:
            pageRange=range(currentPage-5,currentPage+5)

    else:
        pageRange=paginator.page_range


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",locals())
複製代碼

中間件

中間件的概念

中間件顧名思義,是介於request與response處理之間的一道處理過程,相對比較輕量級,而且在全局上改變django的輸入與輸出。由於改變的是全局,因此須要謹慎實用,用很差會影響到性能。

Django的中間件的定義:

1
Middleware  is  a framework of hooks into Django’s request / response processing. <br>It’s a light, low - level 「plugin」 system  for  globally altering Django’s  input  or  output.

若是你想修改請求,例如被傳送到view中的HttpRequest對象。 或者你想修改view返回的HttpResponse對象,這些均可以經過中間件來實現。

可能你還想在view執行以前作一些操做,這種狀況就能夠用 middleware來實現。

你們可能頻繁在view使用request.user吧。 Django想在每一個view執行以前把user設置爲request的屬性,因而就用了一箇中間件來實現這個目標。因此Django提供了能夠修改request 對象的中間件 AuthenticationMiddleware

Django默認的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',
]
複製代碼

每個中間件都有具體的功能。

自定義中間件

中間件中一共有四個方法:

複製代碼
process_request

process_view

process_exception

process_response
複製代碼

process_request,process_response

當用戶發起請求的時候會依次通過全部的的中間件,這個時候的請求時process_request,最後到達views的函數中,views函數處理後,在依次穿過中間件,這個時候是process_response,最後返回給請求者。

上述截圖中的中間件都是django中的,咱們也能夠本身定義一箇中間件,咱們能夠本身寫一個類,可是必須繼承MiddlewareMixin

須要導入

1
from  django.utils.deprecation  import  MiddlewareMixin

 

in views:

def index(request):

    print("view函數...")
    return HttpResponse("OK")

in Mymiddlewares.py:

複製代碼
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
 
    def process_response(self,request,response):
        print("Md1返回")
        return response

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
#return HttpResponse("Md2中斷") def process_response(self,request,response): print("Md2返回") return response
複製代碼

結果:

Md1請求
Md2請求
view函數...
Md2返回
Md1返回

注意:若是當請求到達請求2的時候直接不符合條件返回,即return HttpResponse("Md2中斷"),程序將把請求直接發給中間件2返回,而後依次返回到請求者,結果以下:

返回Md2中斷的頁面,後臺打印以下:

Md1請求
Md2請求
Md2返回
Md1返回

流程圖以下:

 

process_view

1
process_view( self , request, callback, callback_args, callback_kwargs)

 Mymiddlewares.py修改以下

複製代碼
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
        #return HttpResponse("Md1中斷")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md1view")

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
        return HttpResponse("Md2中斷")
    def process_response(self,request,response):
        print("Md2返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md2view")
複製代碼

結果以下:

複製代碼
Md1請求
Md2請求
Md1view
Md2view
view函數...
Md2返回
Md1返回
複製代碼

下圖進行分析上面的過程:

當最後一箇中間的process_request到達路由關係映射以後,返回到中間件1的process_view,而後依次往下,到達views函數,最後經過process_response依次返回到達用戶。

process_view能夠用來調用視圖函數:

複製代碼
class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
        #return HttpResponse("Md1中斷")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):

        # return HttpResponse("hello")

        response=callback(request,*callback_args,**callback_kwargs)
        return response
複製代碼

結果以下:

Md1請求
Md2請求
view函數...
Md2返回
Md1返回

注意:process_view若是有返回值,會越過其餘的process_view以及視圖函數,可是全部的process_response都還會執行。

process_exception

1
process_exception( self , request, exception)

示例修改以下:

複製代碼
class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1請求")
        #return HttpResponse("Md1中斷")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):

        # return HttpResponse("hello")

        # response=callback(request,*callback_args,**callback_kwargs)
        # return response
        print("md1 process_view...")

    def process_exception(self):
        print("md1 process_exception...")



class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2請求")
        # return HttpResponse("Md2中斷")
    def process_response(self,request,response):
        print("Md2返回")
        return response
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("md2 process_view...")

    def process_exception(self):
        print("md1 process_exception...")
複製代碼

結果以下:

複製代碼
Md1請求
Md2請求
md1 process_view...
md2 process_view...
view函數...

Md2返回
Md1返回
複製代碼

流程圖以下:

當views出現錯誤時:

 將md2的process_exception修改以下:

  def process_exception(self,request,exception):

        print("md2 process_exception...")
        return HttpResponse("error")

結果以下:

複製代碼
Md1請求
Md2請求
md1 process_view...
md2 process_view...
view函數...
md2 process_exception...
Md2返回
Md1返回
複製代碼
相關文章
相關標籤/搜索