django】【Python】django中间件的运行机制

2020-12-17 20:23发布

2条回答
我是大脸猫
2楼 · 2020-12-18 09:44
  • 什么是 middleware

  • 什么时候使用 middleware

  • 我们写 middleware 必须要记住的东西

  • 写一些 middlewares 来理解中间件的工作过程和要点

什么是 middleware

Middlewares 是修改 Django request 或者 response 对象的钩子. 下面是Django 文档中的一段描述。

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

什么时候使用 middleware

如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

Django 提供了一些默认的 middleware,例如:
AuthenticationMiddleware

大家可能频繁在view使用request.user吧。 Django想在每个view执行之前把user设置为request的属性,于是就用了一个中间件来实现这个目标。所以Django提供了可以修改request 对象的中间件 AuthenticationMiddleware

Django 这样修改request对象的:

https://github.com/django/django/blob/master/django/contrib/auth/middleware.py#L221

例如你有一个应用,它的用户是不同时区的人们。你想让他们在访问任何页面的时候都能显示正确的时区,想让所有的views中都能得到用户自己的timezone信息。 这种情况下可以用session来解决,所以你可以像下面添加一个 middleware:

class TimezoneMiddleware(object):
    def process_request(self, request):
        # Assuming user has a OneToOneField to a model called Profile
        # And Profile stores the timezone of the User.
        request.session['timezone'] = request.user.profile.timezone12345

TimezoneMiddleware 是依赖于 request.user的,request.user 是通过AuthenticationMiddleware来设置的。 所以在
settings.MIDDLEWARE_CLASSES配置中,TimezoneMiddleware 一定要在 AuthenticationMiddleware 之后。

下面的例子可以得到关于中间件顺序的更多体会。

使用middleware时应该记住的东西

  • middlewares 的顺序非常重要

  • 一个middleware只需要继承 object 类

  • 一个middleware可以实现一些方法并且不需要实现所有的方法

  • 一个middleware可以实现 process_request(方法) 但是不可以实现 process_response(方法) 和 process_view 方法。 这些都很常见,Django提供了很多middlewares可以做到。

  • 一个middleware可以实现 process_response 方法,但是不需要实现 process_request 方法

AuthenticationMiddleware 只实现了对请求的处理,并没有处理响应. 参照文档

GZipMiddleware 只实现了对响应的处理,并没有实现对请求和view的处理 参见文档

写一些 middlewares

首先确认下你有一个Django项目,需要一个url和一个view,并且可以进入这个view。下面我们会对request.user做几个测试,确认权限设置好了,并可以在view中正确打印 request.user 的信息。

在任意一个app中创建middleware.py文件。

我有一个叫做books的app,所以文件的位置是 books/middleware.py

class BookMiddleware(object):
    def process_request(self, request):
        print "Middleware executed"123

MIDDLEWARE_CLASSES 中添加这个中间件

MIDDLEWARE_CLASSES = (    'books.middleware.BookMiddleware',    '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',
)123456789

对任意的一个url发送请求, 下面的信息将会打印在runserver的控制台。

Middleware executed1

修改 BookMiddleware.process_request 如下

class BookMiddleware(object):
    def process_request(self, request):
        print "Middleware executed"
        print request.user1234

再次访问一个url,将会引起一个错误。

'WSGIRequest' object has no attribute 'user'1

这是因为request对象还没有设置user属性呢。

现在我们改变下 middlewares的顺序,BookMiddleware 放在 AuthenticationMiddleware 之后。

MIDDLEWARE_CLASSES = (    'django.contrib.sessions.middleware.SessionMiddleware',    'django.middleware.common.CommonMiddleware',    'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'books.middleware.BookMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)123456789

访问一个url,runserver控制台打印如下

Middleware executed12

这说明middlewares处理request的顺序跟 settings.MIDDLEWARE_CLASSES 中列出的顺序是一致的。

你可以进一步证实,middleware.py添加另外一个middleware

class AnotherMiddleware(object):
    def process_request(self, request):
        print "Another middleware executed"123

把它也加到 MIDDLEWARE_CLASSES

MIDDLEWARE_CLASSES = (    'django.contrib.sessions.middleware.SessionMiddleware',    'django.middleware.common.CommonMiddleware',    'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'books.middleware.BookMiddleware',    'books.middleware.AnotherMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)12345678910

现在的输出是:

Middleware executedAnother middleware executed123

在process_request方法中返回HttpResponse,把BookMiddleware改成下面这样:

class BookMiddleware(object):
    def process_request(self, request):
        print "Middleware executed"
        print request.user        return HttpResponse("some response")12345

尝试下任何一个url,会得到如下输出:

Middleware executed12

你会注意到下面2个事情:

  • 不管你访问哪个url,自己写的view 处理方法都不执行了,只有 “some response”这样一种响应。

  • AnotherMiddleware.process_request 不在被执行

所以如果 Middleware的process_request方法中返回了HttpResponse对象,那么它之后的中间件将被略过, view中的处理方法也被略过。
所以在实际的项目中很少会这么干(不过也有些项目会,例如做代理)

注释掉 "return HttpResponse("some response")",两个 middleware 才能正常的处理请求。

使用 process_response

给这两个middleware添加 process_response方法

class AnotherMiddleware(object):
    def process_request(self, request):
        print "Another middleware executed"

    def process_response(self, request, response):
        print "AnotherMiddleware process_response executed"
        return responseclass BookMiddleware(object):
    def process_request(self, request):
        print "Middleware executed"
        print request.user        return HttpResponse("some response")        #self._start = time.time()

    def process_response(self, request, response):
        print "BookMiddleware process_response executed"
        return response123456789101112131415161718

访问一些url,得到如下的输出

Middleware executedAnother middleware executed
AnotherMiddleware process_response executed
BookMiddleware process_response executed12345

AnotherMiddleware.process_response() 在 BookMiddleware.process_response() 之前执行 而 AnotherMiddleware.process_request() 在 BookMiddleware.process_request()之后执行. 所以process_response() 执行的顺序跟 process_request正好相反. process_response() 执行的顺序是从最后一个中间件执行,到倒数第二个,然后直到第一个中间件.

process_view

Django 按顺序执行中间件 process_view() 的方法,从上到下。 类似process_request()方法执行的顺序。

所以如果任何一个 process_view() 返回了HttpResponse对象,那么在它后面process_view()将会被省略,不会被执行。


我的网名不再改
3楼 · 2020-12-19 19:14

Middlewares 是修改 Django request 或者 response 对象的钩子。中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的过程如下:

也就是说,每一个请求都是先通过中间件中的 process_request 函数,这个函数返回 None 或者 HttpResponse对象,如果返回前者,继续处理其它中间件,如果返回一个 HttpResponse,就处理中止,返回到网页上。


相关问题推荐

  • 回答 19

    Django是一个开放源代码的Web应用框架,由Python写成。采用了MVT的框架模式,即模型M,视图V和模板T。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。并于2005年7月在BSD许可证下发布。这套框架是以比...

  • 回答 1

    使用类似pymysql的第三方模块,在Python代码中嵌入SQL语句,可以直接访问数据库。对于轻量级的SQLite,Django和Python原生支持,连第三方模块都不需要就可以访问。

  • 回答 3
    已采纳

    FlaskFlask确实很轻,不愧是Micro Framework,从Django转向Flask的开发者一定会如此感慨,除非二者均为深入使用过Flask自由、灵活,可扩展性强,第三方库的选择面广,开发时可以结合自己最喜欢用的轮子,也能结合最流行最强大的Python库入门简单,即便没有多...

  • 回答 4
    已采纳

    打开 Linux 或 MacOS 的 Terminal (终端)直接在 终端中输入windows 快捷键 win + R,输入 cmd,直接在 cmd 上输入1、新建一个项目django-admin.py startproject 项目名1以下命令要先进入项目目录下才能执行:cd 项目名2、新建app (一个项目可以有多个app...

  • 回答 5

    Django的默认数据库是sqlite3

  • 回答 3

    Django中避免sql注入的方法:1、对用户的输入进行校验;2、不要使用动态拼装sql;3、不要把机密信息直接存放;4、应用的异常信息应该给出尽可能少的提示;5、利用Dajngo的ORM来有效避免sql注入。什么是SQL注入?所谓SQL注入,就是通过把SQL命令插入到Web表单...

  • 回答 1

    中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能...

  • 回答 1

    项目主要页面介绍1.首页2.注册3.登录2.项目开发模式开发模式前后端不分离后端框架Django+Jinja2模板引擎前端框架Vue.js3.准备项目代码仓库源码托管网站1、码云(https://gitee.com/)2、创建源码远程仓库:website3、克隆项目代码仓库新建文件夹下载githttps:...

  • 回答 3

    from django.http import FileResponsefrom django.utils.encoding import escape_uri_path def build_download_response(filepath, filename):        构建下载文件的文件头    :param filepath: 文件路径    :param filenam...

  • 回答 2

    Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。我们可以使用中间件,在Django处理视图的不同阶段对输入或输出...

  • 回答 10

    django现在在生产环境用得还是比较多的,但是只能说数量比较多,质量很差;意思就是,越大型的项目越不会选django,因为它封装得太好,不够灵活,一般快速上马项目可以,但是长期维护下来很难受一般如果有开发团队的都选flask和tornado...

  • 回答 2

    客户端与服务端交互(知识点)浏览器就是客户端服务端开放端口和连接即可客户端服务器代码实现# -*- coding: utf-8 -*-__author__ = 'HeYang'__time__ = '2018/6/7 2:57'import socket sock = socket.socket()sock.bind(('1...

  • 回答 11

    Django中间件有很多,入session、csrf、contexttype等,能力强的朋友还可以自己写中间件。

  • 回答 4

    django中间件主要有两个作用1·中间件是介于request 和 response 处理之间的一道处理过程,用于全局范围改变Django的输入和输出,简单的来说中间件是帮助我们在视图函数指向之前和执行之后都可以做一些额外的操作2·Django项目中默认启用了csrf保护,每次请求...

  • 回答 7

    中间件 Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。中间件Django中的中间件是一个轻量级、底层的插件系统...

没有解决我的问题,去提问