为啥在 django.utils.deprecation.py 中声明中间件 mixin

Posted

技术标签:

【中文标题】为啥在 django.utils.deprecation.py 中声明中间件 mixin【英文标题】:Why middleware mixin declared in django.utils.deprecation.py为什么在 django.utils.deprecation.py 中声明中间件 mixin 【发布时间】:2019-03-25 14:00:06 【问题描述】:

django.utils.deprecation.py 路径中,我们有一些关于方法弃用警告的类。

在该文件中,我们有一个名为MiddlewareMixin 的类。这个类用来写中间件类。虽然与弃用无关,为什么这个类写在这个路径上?

【问题讨论】:

我认为是因为它将“旧”样式的中间件转换为“新样式”的中间件。 “旧”中间件与process_requestprocess_response 一起使用,但“新”中间件本质上是“下层”之上的装饰器。此 mixin 将旧样式(已弃用)转换为新样式。 【参考方案1】:

简而言之:它是一种将已弃用中间件转变为新中间件的工具,尽管它有一些限制。

Django 的中间件“风格”发生了变化。这个MiddlewareMixin 在大多数情况下可以将旧式中间件类“转换”为新式中间件装饰器,正如documentation on Upgrading pre-Django 1.10-style middleware 中所写:

class django.utils.deprecation.MiddlewareMixin

(...)

在大多数情况下,从这个 mixin 继承足以使旧式中间件与新系统兼容,并具有足够的向后兼容性。新的短路语义将对现有的中间件无害甚至有益。在少数情况下,中间件类可能需要进行一些更改以适应新的语义。

在“旧时代”(django-1.10 之前),中间件的写法如下:

class SomeMiddleware:

    def process_request(self, request):
        # ...
        pass

    def process_response(self, request, response):
        # ...
        return response

但如今,中间件更多地被视为围绕“底层中间件”的某种“装饰器”,最终是视图。如documentation on the new middleware中指定:

中间件可以写成如下所示的函数:
def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

通过引入新的“样式”,您可以看到旧的中间件本身已被“弃用”,这当然是一个遗憾,因为现在所有以前编写的中间件都会被渲染为无效。

MiddlewareMixin 然而能够转换现代中间件中的这种中间件,它通过覆盖__call__ 函数来实现这一点,因此在两者之间调用process_requestprocess_response ,就像我们在source code [GitHub] 中看到的那样:

class MiddlewareMixin:
    def __init__(self, get_response=None):
        self.get_response = get_response
        super().__init__()

    def __call__(self, request):
        response = None
        if hasattr(self, 'process_request'):
            response = self.process_request(request)
        response = response or self.get_response(request)
        if hasattr(self, 'process_response'):
            response = self.process_response(request, response)
        return response

因此,我们通过覆盖__call__ 函数使对象可调用,从而模仿新样式中的def middleware(request) 的工作方式。但是,如果在旧的中间件中,__call__ 也被覆盖,那么这当然会导致一些问题。此外,旧式中间件还有process_viewprocess_exceptionprocess_template_response等函数,这里不再使用。但我认为无论如何这些都不是很“流行”。

【讨论】:

以上是关于为啥在 django.utils.deprecation.py 中声明中间件 mixin的主要内容,如果未能解决你的问题,请参考以下文章

为啥 CoreGui Roblox 锁定在 DataModel 中,为啥受信任的用户不能使用 CoreScripts?

为啥 + 仅在客户端是 NaN?为啥不在 Node.js 中?

在执行语义分割任务时我应该减去图像均值吗?为啥或者为啥不?

为啥我们不能在 TypeScript 类中定义一个 const 字段,为啥静态只读不起作用?

为啥这个函数序言中没有“sub rsp”指令,为啥函数参数存储在负 rbp 偏移处?

为啥这个函数序言中没有“sub rsp”指令,为啥函数参数存储在负 rbp 偏移量?