Django实现一个简单的中间件,不熟悉中间件的爬坑之路

 2023-09-11 阅读 27 评论 0

摘要:1、在之前,写过一篇文章,自定义一个简单的中间件,文章链接如下:https://blog.csdn.net/u012561176/article/details/84024073 后面,发现还是有问题: from django.views import View from django.utils.decorators import method_de

1、在之前,写过一篇文章,自定义一个简单的中间件,文章链接如下:https://blog.csdn.net/u012561176/article/details/84024073

后面,发现还是有问题:

from django.views import View
from django.utils.decorators import method_decorator@method_decorator(LoginMiddleware, name='dispatch')
class AddUser(View):def get(self, request, id):

如上面代码,如果一个View底下的get方法带一个参数或者多个参数的话,将会报错:

__call__() got an unexpected keyword argument 'id'

2、这个__call__()方法是中间件MiddlewareMixin里的方法,自定义中间件的时候可以重写的,在你本地安装路径底下的一个py文件:D:/Python 3.6.3/Lib/site-packages/django/utils/deprecation.py,MiddlewareMixin代码如下:

class MiddlewareMixin:def __init__(self, get_response=None):self.get_response = get_responsesuper().__init__()def __call__(self, request):response = Noneif hasattr(self, 'process_request'):response = self.process_request(request)if not response:response = self.get_response(request)if hasattr(self, 'process_response'):response = self.process_response(request, response)return response

django后端?3、为了解决这个问题,报错说__call__()方法缺少参数,因此我给它加多一个参数,在新建一个中间件,接着调用这个代码如下:

class LoginMiddleware2(MiddlewareMixin):"""自定义权限校验中间件,带多个参数时调用"""def __call__(self, request, *args, **kwargs):return super().__call__(request)def process_request(self, request):"""session是否登录校验检查:param request::return:"""
from django.views import View
from django.utils.decorators import method_decorator@method_decorator(LoginMiddleware2, name='dispatch')
class AddUser(View):def get(self, request, id):

结果还是报错了,报错如下:

get() missing 1 required positional argument: 'id'

4、说这个get方法缺少一个参数id,后面就一直断点底层的东西,发现参数有带过去呀,怎么一直到dispatch那里走进去就报错了,发现是不是这个方法修饰器有问题,还是dispatch方法不行,后面试了好多方法,最后决定还是用别的修饰器看能不能成功,于是打开这个目录底下的一个decorators.py文件:D:/Python 3.6.3/Lib/site-packages/django/utils/decorators.py,代码如下:

"Functions that help with dynamically creating decorators for views."# For backwards compatibility in Django 2.0.
from contextlib import ContextDecorator  # noqa
from functools import WRAPPER_ASSIGNMENTS, update_wrapper, wrapsclass classonlymethod(classmethod):def __get__(self, instance, cls=None):if instance is not None:raise AttributeError("This method is available only on the class, not on instances.")return super().__get__(instance, cls)def method_decorator(decorator, name=''):"""Convert a function decorator into a method decorator"""# 'obj' can be a class or a function. If 'obj' is a function at the time it# is passed to _dec,  it will eventually be a method of the class it is# defined on. If 'obj' is a class, the 'name' is required to be the name# of the method that will be decorated.def _dec(obj):is_class = isinstance(obj, type)if is_class:if name and hasattr(obj, name):func = getattr(obj, name)if not callable(func):raise TypeError("Cannot decorate '{0}' as it isn't a callable ""attribute of {1} ({2})".format(name, obj, func))else:raise ValueError("The keyword argument `name` must be the name of a method ""of the decorated class: {0}. Got '{1}' instead".format(obj, name,))else:func = objdef decorate(function):"""Apply a list/tuple of decorators if decorator is one. Decoratorfunctions are applied so that the call order is the same as theorder in which they appear in the iterable."""if hasattr(decorator, '__iter__'):for dec in decorator[::-1]:function = dec(function)return functionreturn decorator(function)def _wrapper(self, *args, **kwargs):@decoratedef bound_func(*args2, **kwargs2):return func.__get__(self, type(self))(*args2, **kwargs2)# bound_func has the signature that 'decorator' expects i.e.  no# 'self' argument, but it is a closure over self so it can call# 'func' correctly.return bound_func(*args, **kwargs)# In case 'decorator' adds attributes to the function it decorates, we# want to copy those. We don't have access to bound_func in this scope,# but we can cheat by using it on a dummy function.@decoratedef dummy(*args, **kwargs):passupdate_wrapper(_wrapper, dummy)# Need to preserve any existing attributes of 'func', including the name.update_wrapper(_wrapper, func)if is_class:setattr(obj, name, _wrapper)return objreturn _wrapper# Don't worry about making _dec look similar to a list/tuple as it's rather# meaningless.if not hasattr(decorator, '__iter__'):update_wrapper(_dec, decorator)# Change the name to aid debugging.if hasattr(decorator, '__name__'):_dec.__name__ = 'method_decorator(%s)' % decorator.__name__else:_dec.__name__ = 'method_decorator(%s)' % decorator.__class__.__name__return _decdef decorator_from_middleware_with_args(middleware_class):"""Like decorator_from_middleware, but return a functionthat accepts the arguments to be passed to the middleware_class.Use like::cache_page = decorator_from_middleware_with_args(CacheMiddleware)# ...@cache_page(3600)def my_view(request):# ..."""return make_middleware_decorator(middleware_class)def decorator_from_middleware(middleware_class):"""Given a middleware class (not an instance), return a view decorator. Thislets you use middleware functionality on a per-view basis. The middlewareis created with no params passed."""return make_middleware_decorator(middleware_class)()# Unused, for backwards compatibility in Django 2.0.
def available_attrs(fn):"""Return the list of functools-wrappable attributes on a callable.This was required as a workaround for http://bugs.python.org/issue3445under Python 2."""return WRAPPER_ASSIGNMENTSdef make_middleware_decorator(middleware_class):def _make_decorator(*m_args, **m_kwargs):middleware = middleware_class(*m_args, **m_kwargs)def _decorator(view_func):@wraps(view_func)def _wrapped_view(request, *args, **kwargs):if hasattr(middleware, 'process_request'):result = middleware.process_request(request)if result is not None:return resultif hasattr(middleware, 'process_view'):result = middleware.process_view(request, view_func, args, kwargs)if result is not None:return resulttry:response = view_func(request, *args, **kwargs)except Exception as e:if hasattr(middleware, 'process_exception'):result = middleware.process_exception(request, e)if result is not None:return resultraiseif hasattr(response, 'render') and callable(response.render):if hasattr(middleware, 'process_template_response'):response = middleware.process_template_response(request, response)# Defer running of process_response until after the template# has been rendered:if hasattr(middleware, 'process_response'):def callback(response):return middleware.process_response(request, response)response.add_post_render_callback(callback)else:if hasattr(middleware, 'process_response'):return middleware.process_response(request, response)return responsereturn _wrapped_viewreturn _decoratorreturn _make_decoratorclass classproperty:def __init__(self, method=None):self.fget = methoddef __get__(self, instance, cls=None):return self.fget(cls)def getter(self, method):self.fget = methodreturn self

5、从以上代码中,可以看到可以使用另外两个装饰器,分别decorator_from_middleware、decorator_from_middleware_with_args,分别使用如下:

from django.views import View
from django.utils.decorators import method_decorator, decorator_from_middleware@decorator_from_middleware(LoginMiddleware2)
class AddUser(View):def get(self, request, id):
from django.views import View
from django.utils.decorators import method_decorator, decorator_from_middleware, decorator_from_middleware_with_args@decorator_from_middleware_with_args(LoginMiddleware2)
class AddUser(View):def get(self, request, id):

接着还是报错,报错如下:AttributeError: 'function' object has no attribute 'as_view',表示这个注解不能用在as_view那里,于是乎我分别使用在底下的get方法前面,修改代码如下:

from django.views import View
from django.utils.decorators import method_decorator, decorator_from_middlewareclass AddUser(View):@decorator_from_middleware(LoginMiddleware2)def get(self, request, id):

django前后端如何交互,接着报错了:AttributeError: 'AddUser' object has no attribute 'session',说这个对象没有属性session,再试下另外一种咯:

from django.views import View
from django.utils.decorators import method_decorator, decorator_from_middleware, decorator_from_middleware_with_argsclass AddUser(View):@decorator_from_middleware_with_args(LoginMiddleware2)def get(self, request, id):

发现还是报错:_decorator() got an unexpected keyword argument 'id',还是底层抛出来的异常。

6、接着,经过调试摸爬滚打后,终于搞出来了,AttributeError: 'AddUser' object has no attribute 'session',说这个对象没有属性session的时候发现了一个问题:

中间件的request底下才有个request,那个request才有session属性,所以,我修改一下中间件如下:

class LoginMiddleware2(MiddlewareMixin):"""自定义权限校验中间件, 带多个参数时"""def process_request(self, request):""":param request::return:"""if login_view.login_check(request.request) is not True:return login_view.login_check(request.request)

django中间件的五个方法?要调的时候加多一个request.即可,因为是中间件的request底下还有request,接着再调用即可,

from django.views import View
from django.utils.decorators import method_decorator, decorator_from_middlewareclass AddUser(View):@decorator_from_middleware(LoginMiddleware2)def get(self, request, id):

7、以上内容就是我的中间件爬坑之路,大家可以慢慢看,以上内容仅供大家学习参考,谢谢!

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/47379.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息