1. Django生命周期

django的生命周期是:前端请求—>nginx—>uwsgi.—>中间件—>url路由---->view视图—>orm---->拿到数据返回给view---->视图将数据渲染到模版中拿到字符串---->中间件—>uwsgi---->nginx---->前端渲染。

2. Django中间件

Django 中间件是修改 Django request 或者 response 对象的钩子,可以理解为是介于 HttpRequest 与 HttpResponse 处理之间的一道处理过程。
浏览器从请求到响应的过程中,Django 需要通过很多中间件来处理,可以看如下图所示:

2.1 内置中间件

  1. django.middleware.security.SecurityMiddleware
做了一些安全处理的中间件。比如设置防御的请求头,比如做了http协议转为https协议的工作等。
  1. django.contrib.sessions.middleware.SessionMiddleware
session中间件。会给request添加一个处理好的session对象。
  1. django.middleware.common.CommonMiddleware
通用中间件,会处理一些URL,比如baidu.com会自动的处理成www.baidu.com。比如/blog/111会处理成/blog/111/自动加上反斜杠。
  1. django.middleware.csrf.CsrfViewMiddleware
保护中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。SessionMiddleware必须出现在CsrfMiddleware之前。
  1. django.contrib.auth.middleware.AuthenticationMiddleware
用户授权中间件。会给request添加一个user对象的中间件。该中间件必须在sessionmiddleware后面。
  1. django.contrib.messages.middleware.MessageMiddleware
消息处理中间件。为了在多个模板中可以使用我们返回给模板的变量,并且简化操作。
  1. django.middleware.clickjacking.XFrameOptionsMiddleware
防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。

中间件组件配置在 settings.py 文件的 MIDDLEWARE 选项列表中,配置中的每个字符串选项都是一个类,也就是一个中间件。Django 默认的中间件配置如下:

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.2 自定义中间件

中间件可以定义五个方法,分别是:

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_request和process_response,在自己定义中间件时,必须继承MiddlewareMixin,自定义中间件步骤如下:
①在应用(app1)下创建myMiddleWare.py文件,定义中间件类;

#文件名:myMiddleWare.py
from django.utils.deprecation import MiddlewareMixin

class thCheck(MiddlewareMixin):
    def process_request(self, request):
        print(8848)

    def process_response(self, request, response):
        print(9999)
        return response

②注册自定义中间件;

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",
    "app1.myMiddleWare.thCheck",  # 自定义的中间件
]

③在app1.views.py中定义视图函数index:

#文件名:app1.views.py
from django.shortcuts import render
from django.http import HttpResponse

from app1.models import Test

# Create your views here.

# 用作测试的视图函数
def index(request):
    print("执行index视图函数...")
    return HttpResponse("index")


def function1(request):
    t = Test(name="func1", age=8)
    t.save()
    return HttpResponse("function1")


def function2(request):
    t = Test(name="func2", age=4)
    t.save()
    return HttpResponse("function2")

④测试:在浏览器中访问http://127.0.0.1:8000/api/app1/index,终端打印如下信息:

3. 典型应用案例

①限制访问频率(每分钟最多访问10次)
②验证是否登录(未登录用户转到login界面)

3.1 定义中间件

为了实现限制访问频率和验证登录两个功能,分别定义中间件AccessFrequencyMiddleware和LoginRequireMiddleware:

文件名:app1.myMiddleWare.py
import time
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.utils.deprecation import MiddlewareMixin
from django.urls import reverse


class User(object):
    def __init__(self, ip):
        self.ip = ip
        self.reset()

    def reset(self):
        self.first_time = time.time()
        self.counter = 1

# {ip:User()}
user_dict = {}


class AccessFrequencyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        remote_ip = request.META.get('REMOTE_ADDR')
        if remote_ip not in user_dict:
            # 用户首次访问
            user_dict[remote_ip] = User(remote_ip)
        else:
            user = user_dict.get(remote_ip)
            time_interval = time.time() - user.first_time
            user.counter += 1
            if time_interval < 60 and user.counter > 10:
                user.last_time = time.time()
                user.is_forbidden = True
                return HttpResponse('访问频率过高,限制访问')
            elif time_interval > 60:
                user.reset()
            else:
                pass


class LoginRequireMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
        super().__init__(get_response)
        self.get_response = get_response
        self.white_list = ["/login/", "/register/"]  # 白名单
        self.black_list = []  # 黑名单

    def process_request(self, request):
        path = request.path
        print(path, request.user.is_authenticated)
        if request.user.is_authenticated or path in self.white_list:
            return None
        elif path in self.black_list:
            return JsonResponse({"code": 0, "error": "禁止访问"}, status=403)
        else:
            # viewname 可以是在path()中定义的路由别名name,通过reverse(viewname)函数可以反向查找URL
            return HttpResponseRedirect(reverse('login-view'))

3.2 注册自定义中间件

文件名:django_study.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",
    "app1.myMiddleWare.AccessFrequencyMiddleware",
    "app1.myMiddleWare.LoginRequireMiddleware",
]

3.3 定义登录视图函数

在django_study工程路径下添加views.py程序,编写登录视图函数:

文件名:django_study.views.py
from django.http import HttpResponse


def login(request):
    print("请登录...")
    return HttpResponse("登录界面")

3.3 注册视图函数对应的URL

文件名:django_study.urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include

import app1.urls as app1_urls
import app2.urls as app2_urls
from .views import *

urlpatterns = [
    path("admin/", admin.site.urls),
    path("login/", login, name="login-view"),  #视图函数URL
    path("api/app1/", include(app1_urls)),
    path("api/app2/", include(app2_urls)),
]

3.4 测试


追忆
6 声望1 粉丝