Django - 中間件

2. 今日內容

    https://www.cnblogs.com/liwenzhou/p/8761803.html
    https://www.cnblogs.com/liwenzhou/p/8761803.html

    HTTP:
    請求格式:
    HTTP/1.1 /index    GET \r\n
    k1:v1 \r\n
    ...
    請求體

    響應格式
    HTTP/1.1 200 OK
    K1:V1 \r\n
    Content-Type:'text/html;charset=utf-8 \r\n
    ...
    響應體
        圖-------------------

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


    0. Django的請求流程圖
     importlib 模塊
    1.中間件(酌情使用!!!)  每一個請求都要過中間件 多了 慢
    學習的關鍵就是:
        五個相關方法,在請求生命週期的什麼時候按照何種順序執行!!!!!
            1. process_request(self, request)
                - 視圖函數執行以前(在urls.py找對應關係以前)
                - 註冊順序
            2. process_response(self, request, response)
                - 視圖函數執行以後
                - 註冊順序的倒序

            3. process_view(self, view_func, view_args, view_kwargs)
                - 視圖函數執行以前(在urls.py中找到對應關係以後)
                    此時view_func就是將要執行的視圖函數對象!!!
                - 註冊順序
            4. process_exception(self, request, exception)
                - 視圖函數執行以後,只有在有異常的時候才執行
                - 註冊順序的倒序

            5. process_template_response(self, request, response)  (csrf-token就是在這個中間件裏面寫的)
                - 視圖函數執行以後,只有在響應對象有render方法的時候才執行
                - 註冊順序的倒序

            m1.process_request    return none ...往下走  return response 不走後面了
            m2.process_request
            url
            m1.process_view
            m2.process_view
            view
            orm  / template
            m2.process_exception           return response
            // 有異常纔會調用  raise ValueError('hehe,拋異常')
            m1.process_exception
            m2.process_template_response    return response
            // 返回對象有render方法時 纔會調用
            m1.process_template_response
            m2.process_response
            m1.process_response

            兩張 圖-------


    2. Django項目logging模塊的配置和使用

    https://www.cnblogs.com/liwenzhou/p/8763264.html


3. 做業
    1. 中間件版的登陸校驗(博客有答案,本身寫完再看)
    2. 本身去查資料學習下importlib模塊(培養本身的自學能力)
    3. 祝大家幸福!
筆記

前戲:html

前面的內容已經學會了給視圖函數加裝飾器來判斷是用戶是否登陸,把沒有登陸的用戶請求跳轉到登陸頁面。咱們經過給幾個特定視圖函數加裝飾器實現了這個需求。可是之後添加的視圖函數可能也須要加上裝飾器,這樣是否是稍微有點繁瑣。sql

學完今天的內容以後呢,咱們就能夠用更適宜的方式來實現相似給全部請求都作相同操做的功能了。數據庫

1、中間件介紹

什麼是中間件?django

官方的說法:中間件是一個用來處理Django的請求和響應的框架級別的鉤子。它是一個輕量、低級別的插件系統,用於在全局範圍內改變Django的輸入和輸出。每一箇中間件組件都負責作一些特定的功能。瀏覽器

可是因爲其影響的是全局,因此須要謹慎使用,使用不當會影響性能。session

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

咱們一直都在使用中間件,只是沒有注意到而已,打開Django項目的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',
]

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

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

那接下來就學習中間件中的方法以及這些方法何時被執行。

2、自定義中間件

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

  • 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對象,則直接將該對象返回給用戶。

自定義一箇中間件示例:

from django.utils.deprecation import MiddlewareMixin


class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1裏面的 process_request")

    def process_response(self, request, response):
        print("MD1裏面的 process_response")
        return response

3、process_request

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

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

咱們來看看多箇中間件時,Django是如何執行其中的process_request方法的。

from django.utils.deprecation import MiddlewareMixin


class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1裏面的 process_request")


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2裏面的 process_request")
        pass

在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
app01 中的 index視圖

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

MD2裏面的 process_request
MD1裏面的 process_request
app01 中的 index視圖

看結果咱們知道:視圖函數仍是最後執行的,MD2比MD1先執行本身的process_request方法。

在打印一下兩個自定義中間件中process_request方法中的request參數,會發現它們是同一個對象。

由此總結一下:

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

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

4、process_response

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

給上述的M1和M2加上process_response方法:

from django.utils.deprecation import MiddlewareMixin


class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1裏面的 process_request")

    def process_response(self, request, response):
        print("MD1裏面的 process_response")
        return response


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2裏面的 process_request")
        pass

    def process_response(self, request, response):
        print("MD2裏面的 process_response")
        return response

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

MD2裏面的 process_request
MD1裏面的 process_request
app01 中的 index視圖
MD1裏面的 process_response
MD2裏面的 process_response

看結果可知:

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

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

5、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


class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1裏面的 process_request")

    def process_response(self, request, response):
        print("MD1裏面的 process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("MD1 中的process_view")
        print(view_func, view_func.__name__)


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2裏面的 process_request")
        pass

    def process_response(self, request, response):
        print("MD2裏面的 process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("MD2 中的process_view")
        print(view_func, view_func.__name__)

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

MD2裏面的 process_request
MD1裏面的 process_request
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x000001DE68317488> index
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x000001DE68317488> index
app01 中的 index視圖
MD1裏面的 process_response
MD2裏面的 process_response

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

6、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


class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1裏面的 process_request")

    def process_response(self, request, response):
        print("MD1裏面的 process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("MD1 中的process_view")
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(exception)
        print("MD1 中的process_exception")


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2裏面的 process_request")
        pass

    def process_response(self, request, response):
        print("MD2裏面的 process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("MD2 中的process_view")
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(exception)
        print("MD2 中的process_exception")

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

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

def index(request):
    print("app01 中的 index視圖")
    raise ValueError("呵呵")
    return HttpResponse("O98K")

在MD1的process_exception中返回一個響應對象:

class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1裏面的 process_request")

    def process_response(self, request, response):
        print("MD1裏面的 process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("MD1 中的process_view")
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(exception)
        print("MD1 中的process_exception")
        return HttpResponse(str(exception))  # 返回一個響應對象

看輸出結果:

MD2裏面的 process_request
MD1裏面的 process_request
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x0000022C09727488> index
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x0000022C09727488> index
app01 中的 index視圖
呵呵
MD1 中的process_exception
MD1裏面的 process_response
MD2裏面的 process_response

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

7、process_template_response(用的比較少)

process_template_response(self, request, response)

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

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

class MD1(MiddlewareMixin):

    def process_request(self, request):
        print("MD1裏面的 process_request")

    def process_response(self, request, response):
        print("MD1裏面的 process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("MD1 中的process_view")
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(exception)
        print("MD1 中的process_exception")
        return HttpResponse(str(exception))

    def process_template_response(self, request, response):
        print("MD1 中的process_template_response")
        return response


class MD2(MiddlewareMixin):
    def process_request(self, request):
        print("MD2裏面的 process_request")
        pass

    def process_response(self, request, response):
        print("MD2裏面的 process_response")
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):
        print("-" * 80)
        print("MD2 中的process_view")
        print(view_func, view_func.__name__)

    def process_exception(self, request, exception):
        print(exception)
        print("MD2 中的process_exception")

    def process_template_response(self, request, response):
        print("MD2 中的process_template_response")
        return response

views.py中:

def index(request):
    print("app01 中的 index視圖")

    def render():
        print("in index/render")
        return HttpResponse("O98K")
    rep = HttpResponse("OK")
    rep.render = render
    return rep

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

MD2裏面的 process_request
MD1裏面的 process_request
--------------------------------------------------------------------------------
MD2 中的process_view
<function index at 0x000001C111B97488> index
--------------------------------------------------------------------------------
MD1 中的process_view
<function index at 0x000001C111B97488> index
app01 中的 index視圖
MD1 中的process_template_response
MD2 中的process_template_response
in index/render
MD1裏面的 process_response
MD2裏面的 process_response

從結果看出:

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

8、中間件的執行流程

上一部分,咱們瞭解了中間件中的5個方法,它們的參數、返回值以及何時執行,如今總結一下中間件的執行流程。

請求到達中間件以後,先按照正序執行每一個註冊中間件的process_reques方法,process_request方法返回的值是None,就依次執行,若是返回的值是HttpResponse對象,再也不執行後面的process_request方法,而是執行當前對應中間件的process_response方法,將HttpResponse對象返回給瀏覽器。也就是說:若是MIDDLEWARE中註冊了6箇中間件,執行過程當中,第3箇中間件返回了一個HttpResponse對象,那麼第4,5,6中間件的process_request和process_response方法都不執行,順序執行3,2,1中間件的process_response方法。

process_request方法都執行完後,匹配路由,找到要執行的視圖函數,先不執行視圖函數,先執行中間件中的process_view方法,process_view方法返回None,繼續按順序執行,全部process_view方法執行完後執行視圖函數。加入中間件3 的process_view方法返回了HttpResponse對象,則4,5,6的process_view以及視圖函數都不執行,直接從最後一箇中間件,也就是中間件6的process_response方法開始倒序執行。

process_template_response和process_exception兩個方法的觸發是有條件的,執行順序也是倒序。總結全部的執行流程以下:

 

 

Django請求流程圖

 

 

9、中間件版的登陸驗證

中間件版的登陸驗證須要依靠session,因此數據庫中要有django_session表。

urls.py

from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^index/$', views.index),
    url(r'^login/$', views.login, name='login'),
]

views.py

from django.shortcuts import render, HttpResponse, redirect


def index(request):
    return HttpResponse('this is index')


def home(request):
    return HttpResponse('this is home')


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        if user == "Q1mi" and pwd == "123456":
            # 設置session
            request.session["user"] = user
            # 獲取跳到登錄頁面以前的URL
            next_url = request.GET.get("next")
            # 若是有,就跳轉回登錄以前的URL
            if next_url:
                return redirect(next_url)
            # 不然默認跳轉到index頁面
            else:
                return redirect("/index/")
    return render(request, "login.html")

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>登陸頁面</title>
</head>
<body>
<form action="{% url 'login' %}">
    <p>
        <label for="user">用戶名:</label>
        <input type="text" name="user" id="user">
    </p>
    <p>
        <label for="pwd">密 碼:</label>
        <input type="text" name="pwd" id="pwd">
    </p>
    <input type="submit" value="登陸">
</form>
</body>
</html>

middlewares.py

class AuthMD(MiddlewareMixin):
    white_list = ['/login/', ]  # 白名單
    balck_list = ['/black/', ]  # 黑名單

    def process_request(self, request):
        from django.shortcuts import redirect, HttpResponse

        next_url = request.path_info
        print(request.path_info, request.get_full_path())

        if next_url in self.white_list or request.session.get("user"):
            return
        elif next_url in self.balck_list:
            return HttpResponse('This is an illegal URL')
        else:
            return redirect("/login/?next={}".format(next_url))

在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',
    'middlewares.AuthMD',
]

AuthMD中間件註冊後,全部的請求都要走AuthMD的process_request方法。

訪問的URL在白名單內或者session中有user用戶名,則不作阻攔走正常流程;

若是URL在黑名單中,則返回This is an illegal URL的字符串;

正常的URL可是須要登陸後訪問,讓瀏覽器跳轉到登陸頁面。

注:AuthMD中間件中須要session,因此AuthMD註冊的位置要在session中間的下方。

10、示例

 

my_middleware.py

# -*- coding:utf-8 -*-
'''
自定義中間件文件

'''
from django.utils.deprecation import MiddlewareMixin
from django.http import HttpResponse

class MD1(MiddlewareMixin):

    # 處理請求
    def process_request(self,request):
        print('這裏是MD1裏面的中間件 process_request')
        # print(request.method)
        # print(id(request))
        # request.s9 = 'hehe'
        # rep = HttpResponse('快走')
        # return rep
        # 只能返回 None / HttpResponse  默認返回 None 進入下一個中間件

    # 處理響應
    def process_response(self,request,response):
        print('md1裏面的 process_response')
        return response  # 必須返回 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')

    # 中間件 中央處理模板響應
    def process_template_response(self, request, response):
        print('md1 中央處理模板響應')
        return response  # 必須返回 response


class MD2(MiddlewareMixin):

    # 處理請求
    def process_request(self,request):
        print('這裏是MD2裏面的中間件 process_request')
        # print(id(request))
        # print(request.s9)

    # 處理響應
    def process_response(self,request,response):
        print('md2裏面的 process_response')
        return response  # 必須返回response
        # rep = HttpResponse('hehe nihao ')  # 這裏可修改 返回的響應 哇!!
        # return rep

    def process_view(self, request, view_func, view_args, view_kwargs):
        '''
        :param request:    請求對象
        :param view_func:  將要執行的視圖函數
        :param view_args:  將要執行的視圖函數的位置參數
        :param view_kwargs:將要執行的視圖函數的關鍵字參數
        :return:
        '''
        print(view_func)
        print(view_func.__doc__)
        print(view_func.__name__)
        print('MD2 中的process_view')
        # 直接在中間件執行函數
        # ret = view_func(request)
        # return ret

    # 發生異常時 執行 有raise 方法調用
    def process_exception(self, request, exception):
        '''
        異常
        :param request:
        :param exception:
        :return:
        '''
        print('*'*120)
        print(exception)
        print('*' * 120)
        print('md2中的 process_exception')

        # return HttpResponse(str(exception))

    # 中間件 中央處理模板響應 有render 方法調用
    def process_template_response(self, request, response):
        print('md2 中央處理模板響應')
        return response



# 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)

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

'''
my_middleware

settimgs.py

"""
Django settings for about_middleware project.

Generated by 'django-admin startproject' using Django 2.0.1.

For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 's011rs!(ga_n!j#*1@!-c2is3)xaw()87bpj=ffjhel^$vzi5v'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True  # 真正上線 這是 false

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
]

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

    # 註冊兩個自定義的中間件
    'my_middleware.MD1',
    'my_middleware.MD2',

]
# 中間件 https://www.cnblogs.com/liwenzhou/p/8761803.html

from django.middleware.security import SecurityMiddleware
from django.middleware.csrf import CsrfViewMiddleware
from django.middleware.clickjacking import XFrameOptionsMiddleware

# 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)



ROOT_URLCONF = 'about_middleware.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'about_middleware.wsgi.application'


# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = '/static/'

# https://www.cnblogs.com/liwenzhou/p/8763264.html
# django 的日誌配置項
BASE_LOG_DIR = os.path.join(BASE_DIR,'log')
LOGGING = {
    'version': 1,  # 保留字
    'disable_existing_loggers': False,  # 禁用已經存在的 logger 實例
    'formatters': {
        # 詳細的日誌格式
        'standard': {
            'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
                      '[%(levelname)s][%(message)s]'
        },
        # 簡單的日誌格式
        'simple': {
            'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
        },
        # 定義一個特殊的日誌格式
        'collect': {
            'format': '%(message)s'
        }
    },
    # 過濾器
    'filters': {
        # DEBUG = True 的狀況 才過濾
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    # 處理器
    'handlers': {
        # 在終端打印
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],  # 只有在Django debug爲True時纔在屏幕打印日誌
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        # 默認
        'default': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自動切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"),  # 日誌文件
            'maxBytes': 1024 * 1024 * 50,  # 日誌大小 50M 通常配500M
            'backupCount': 3, # 最多備份3個
            'formatter': 'standard',
            'encoding': 'utf-8',
        },
        # 專門用來記 錯誤日誌
        'error': {
            'level': 'ERROR',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自動切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"),  # 日誌文件
            'maxBytes': 1024 * 1024 * 50,  # 日誌大小 50M
            'backupCount': 5,
            'formatter': 'standard',
            'encoding': 'utf-8',
        },
        # 專門 定義一個 收集特定信息的日誌
        'collect': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自動切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"),
            'maxBytes': 1024 * 1024 * 50,  # 日誌大小 50M
            'backupCount': 5,
            'formatter': 'collect',
            'encoding': "utf-8"
        }
    },
    'loggers': {
       # 默認的logger應用以下配置
        '': {
            'handlers': ['default', 'console', 'error'],  # 上線以後能夠把'console'移除
            'level': 'DEBUG',
            'propagate': True,  # 向不向更高級別的logger傳遞
        },
        # 名爲 'collect'的logger還單獨處理
        'collect': {
            'handlers': ['console', 'collect'],
            'level': 'INFO',
        }
    },
}
settings

urls.py

from django.contrib import admin
from django.urls import path

from app01 import views
urlpatterns = [
    path('index/', views.index),
]
urls

views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

import logging
# 生成一個以當前文件名爲名字的logger實例
logger = logging.getLogger(__name__)
collect_logger = logging.getLogger('collect') # 生成一個名爲collect的實例

def index(requset):
    logger.debug('一個debug萌萌的請求...')
    logger.info('一個info萌萌的請求...')
    '''
    這是視圖函數index的doc信息
    :param requset:
    :return:
    '''
    print('@'*120)
    print('這是app01裏面的index函數')
    # print(requset.s9)

    # raise ValueError('hehe,拋異常')

    # return HttpResponse('OK')

    rep = HttpResponse('OK')
    collect_logger.info('這是collect_logger日誌')
    collect_logger.info('hello:collect')

    # def render():
    #     return HttpResponse('不經常使用')
    #
    # rep.render = render
    return rep
views
相關文章
相關標籤/搜索