我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Django之中间件

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Django之中间件

中间件介绍

 

中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。

 

但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。

 

说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在处理请求的特定的时间去执行这些方法。

  在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配置项是一个列表,列表中是一个个字符串,这些字符串其实是一个个类,也就是一个个中间件.

我们之前已经接触过一个csrf相关的中间件了?我们一开始让大家把他注释掉,再提交post请求的时候,就不会被forbidden了,后来学会使用csrf_token之后就不再注释这个中间件了。

 

自定义中间件

  中间件可以定义五个方法,分别是:(主要的是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定义的规则向后继续执行,如果是HttResponse对象,则直接将该对象返回给用户.

 

示例

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

 

process_request方法

 

  参数: request  (和视图函数中的request是一样的)

  返回值: None 返回值是None,按正常流程走,交给下一个中间件;

       HttpResponse对象 若是此值,Django将不执行当前中间件后面的中间件的process_request方法和视图函数,执行当前中间件的process_response方法或之前中间件的process_response方法.

  执行时间:  该中间件方法是在视图函数执行前执行;

  执行顺序:  配置多个中间件时,按照注册顺序的先后顺序执行.

 

 当多个中间件时 ,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")

 

  在Setting.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路径
]

 

 

  接着访问一个视图,终端打印内容如下:

MD2里面的 process_request
MD1里面的 process_request
app01 中的 index视图

  结果得知: 视图函数还是最后执行,MD2比MD1先执行自己的process_request方法.  不同中间件之间传递的request都是同一个对象

 

process_response方法

 

  参数: request  视图函数中用到的request 

      response  视图函数返回的HttpResponse对象.

  执行时间  在视图函数执行之后

  执行顺序  多个中间件的process_response方法是按照执行顺序的倒序执行

  返回值  必须是response(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")

    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方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。

 

process-view方法

 

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

  参数: request;

      view_func:  是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。);

      view_args:  是将传递给视图的位置参数;

      view_kwargs:   是将传递给视图的关键字参数。 view_args和view_kwargs都不包含第一个视图参数(request);

  返回值:   None Django将继续处理这个请求,执行任何其他中间件的process_view 方法,然后在执行相应的视图.

      HttpResponse对象. 如果返回一个HttPResponse对象,Django不会调用适当的视图函数. 他将执行中间件的process_response方法并将应用到该HttpResponse并返回结果.

  执行时间: 在视图函数之前,process_request之后

  执行顺序:   按照注册顺序先后执行

 

给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")

    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中注册顺序从前到后顺序执行的.

 

process_exception(self, request, exception)方法

 

 参数:

  HttpRequest对象

  exception  是视图函数异常产生的Exception对象.

  执行时间:  在视图函数之后,process_response方法之前       这个方法只有在视图函数中出现异常了才执行,

  返回值: None 交给下一个中间件的process_exception方法来处理异常.

       HttpResponse对象 Django将执行所有中间件的process_response方法; 该中间件方法注册之前的中间件的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")

    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方法直接返回了一个响应对象.

 

process_template-response方法

 

process-template_response(self, request, response)

  参数 HttpRequest对象,

     response  TemplateResponse对象(由视图函数或者中间件产生).

  执行时间  是在视图函数执行完成后立即执行,但是他有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法).

  执行顺序  按照注册顺序倒序执行

  返回值  response对象

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") 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_response方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法.

 

中间件的执行流程

请求到达中间件之后,先按照正序执行每个注册中间件的process_request方法,process_request方法返回的值是None,就依次执行,如果返回的是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_request方法,将HttpResponse对象返回给浏览器.也就是说MIDDLEMARE中注册了六个中间件,执行过程中,第三个中间件返回Response对象,那么第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俩个方法的触发是有条件的,执行顺序也是倒序.总结所有的执行流程如下:

中间件登录验证

 

中间件版的登录验证需要session,所以数据库中药有django_session表

urls.py

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

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

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 == "alex" and pwd == "alex3714":
            # 设置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' %}" method="post">
    {% csrf_token %}
    <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

from django.utils.deprecation import MiddlewareMixin


class AuthMD(MiddlewareMixin):
    white_list = ['/login/', ]  # 白名单
    black_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.black_list:
            return HttpResponse('This is an illegal URL')
        # 白名单的网址或者登陆用户不做限制
        elif next_url in self.white_list or request.session.get("user"):
            return
        else:
            return redirect("/login/?next={}".format(next_url))

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

AuthMD中间件注册后,所有的请求都要走AuthMD的process_request方法。

如果URL在黑名单中,则返回This is an illegal URL的字符串;

访问的URL在白名单内或者session中有user用户名,则不做阻拦走正常流程;

正常的URL但是需要登录后访问,让浏览器跳转到登录页面。

注:AuthMD中间件中需要session,所以AuthMD注册的位置要在session中间的下方.

 

Django请求流程图

正常过程 : 浏览器发请求---wsgi封装成HttpRequest对象---中间件的process_request方法---路由匹配---中间件中的process_view方法---视图函数---模板(Template) | Model | 有HttpResponse对象,就执行process_response方法.

特殊情况: 示图某方法有返回response对象,就会执行process_response方法;

     出现错误就会执行exception方法处理,若都出现错误,Django会处理错误,处理完成后还要执行process_response方法.

 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Django之中间件

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Django之中间件

中间件介绍 中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。 但是由于其影响的是全局,所以需要谨慎使用,使用不
2023-01-30

day 63 Django基础九之中间件

本节目录一 前戏二 中间件介绍三 自定义中间件四 中间件的执行流程五 中间件版登陆认证六 xxx七 xxx八 xxx一 前戏    我们在前面的课程中已经学会了给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面。我们
2023-01-31

Django 中间件

目录 一.中间件 二.中间件用途 三.中间件方法 四.自定义中间件 process_view process_exception
2023-01-30

django中间件-12

目录 自定义中间件 函数定义 类定义 中间件的执行顺序 在django中,中间件其实就是一个类,他是一个可以介入djang
2023-01-30

Django中间件的使用

中间件(middleware)中间件应用于request与服务端之间和服务端与response之间,客户端发起请求到服务端接收可以通过中间件,服务端返回响应与客户端接收响应可以通过中间件,也就是说中间件可以处理request和respons
2023-01-30

Django 中间件 请求前

中间件:class TestMiddleware(object): """中间件类""" def __init__(self): """服务器重启之后,接收第一个请求时调用""" pass
2023-01-30

Django的中间件是什么

本篇内容主要讲解“Django的中间件是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Django的中间件是什么”吧!什么是中间件(middleware) django 中的中间件(midd
2023-06-04

Django——中间件设置缓存

如图所示查看网站缓存时间在app中创建middleware.py文件,导入MiddlewareMixin,创建类并继承MiddlewareMixin在settings中的MIDDLEWARE=[ ] 注册中间件类;添加一个CACHE_CON
2023-01-30

Django之auth组件

一、Auth模块是什么  django内置的用户认证系统 ,可以快速 的实现,登录,注销,修改密码...二、Auth用法:  1、先创建超级用户 :    python3 manage.py createsuperuser;输入用户名,邮箱
2023-01-30

Django之forms组件

一、校验数据功能  我们在写注册页面时,之前只是提交了数据,然后就保存了数据,后端根本就没有对数据进行校验,比如价格写的不是纯数字也让保存,这肯定是不行的,在前端是可以校验的,但我们不能只依靠前端验证,万一前端不校验,那整个过程就没校验了,
2023-01-30

Django之Form组件

一 Form介绍    我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。  与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不
2023-01-30

Django之频率组件

一、频率简介为了控制用户对某个url的请求 的频率,比如 ,一分钟以内,只能访问三次二、自定义频率类,自定义频率规则自定义的逻辑(1)取出访问者的ip(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里
2023-01-30

Django之Ajax文件上传

请求头ContentType    ContentType指的是请求体的编码类型,常见的类型共有3种:    1 application/x-www-form-urlencoded(看下图)      这应该是最常见的 POST 提交数据的
2023-01-30

Django之用户认证组件

用户认证组件用的是Django自带一个表:auth_user  一、auth模块  1,authenticate()判断用户是否存在方法user=authenticate(username='xxx',password='xxxx')
2023-01-30

django中间件的运行机制是什么

Django中间件是一个轻量级、插件化的系统,用于处理请求和响应的过程。中间件是一个Python类,包含处理请求、处理响应或在视图函数执行前后执行的方法。Django中间件的运行机制如下:当一个请求到达Django应用时,中间件会按照顺序
django中间件的运行机制是什么
2024-03-04

django-10-中间件和上下文管理器

<<<中间件的引入>>> 用户<->中间件<->url->视图 在app目录里面 middleware.py (1)中间件就是一个可调用的对象,接受一个request并返回一个请求 (2)一个中间件可以是一个函数,参数必须要是get_res
2023-01-31

Django学习之八:forms组件【对

目录 Django forms组件 bound and unbound form instance forms渲染有关 隐藏一个字段,不渲染它
2023-01-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录