在视图层中,基于函数的视图叫FBV(function base views),基于类的视图叫CBV(class base views)。当需要用到装饰器时,例如之前的基于Cookie与基于Session的登录验证,给FBV加装饰器很简单,一个@语法糖就OK了,那么给CBV加装饰器呢,难道直接跟单例实现的方法之一一样,类上面一个@语法糖就行了吗。其实给CBV加装饰器有三种方法。
需要先导入模块:
from django.utils.decorators import method_decorator
装饰类时,语法为:@method_decorator(装饰器函数名, name=‘类内需要装饰的方法名’),
直接装饰类内的方法时,直接@method_decorator(装饰器函数名)即可。我们这里不用原生的装饰器是因为扩展性差,因为类方法有一个self参数,如果用原生的装饰器就需要加一个参数,可是加了之后装饰器又没法装饰普通的函数了。
# @method_decorator(login_auth,name='get') # 第二种 name参数必须指定 class MyHome(View): @method_decorator(login_auth) # 第三种 get和post都会被装饰 def dispatch(self, request, *args, **kwargs): super().dispatch(request,*args,**kwargs) # @method_decorator(login_auth) # 第一种 def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')
二. 中间件
看中间件之前,先看一下Django生命周期:
1. 什么是中间件
中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。
但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。
说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。
中间件就像是Django的门户,数据在进入与离开时都要经过中间件。
2. Django默认的中间件及中间件的五种方法
Django默认有七种中间件,可以在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', ]
有兴趣可以看一下各中间件的源码(注意:以该种方式看完源码后要运行Django项目,记得把它们给注释或者删除了,不然会报Apps aren't loaded yet.等错误):
import re from django.conf import settings from django.http import HttpResponsePermanentRedirect from django.utils.deprecation import MiddlewareMixin class SecurityMiddleware(MiddlewareMixin): def __init__(self, get_response=None): self.sts_seconds = settings.SECURE_HSTS_SECONDS self.sts_include_subdomains = settings.SECURE_HSTS_INCLUDE_SUBDOMAINS self.sts_preload = settings.SECURE_HSTS_PRELOAD self.content_type_nosniff = settings.SECURE_CONTENT_TYPE_NOSNIFF self.xss_filter = settings.SECURE_BROWSER_XSS_FILTER self.redirect = settings.SECURE_SSL_REDIRECT self.redirect_host = settings.SECURE_SSL_HOST self.redirect_exempt = [re.compile(r) for r in settings.SECURE_REDIRECT_EXEMPT] self.get_response = get_response def process_request(self, request): path = request.path.lstrip("/") if (self.redirect and not request.is_secure() and not any(pattern.search(path) for pattern in self.redirect_exempt)): host = self.redirect_host or request.get_host() return HttpResponsePermanentRedirect( "https://%s%s" % (host, request.get_full_path()) ) def process_response(self, request, response): if (self.sts_seconds and request.is_secure() and 'strict-transport-security' not in response): sts_header = "max-age=%s" % self.sts_seconds if self.sts_include_subdomains: sts_header = sts_header + "; includeSubDomains" if self.sts_preload: sts_header = sts_header + "; preload" response["strict-transport-security"] = sts_header if self.content_type_nosniff and 'x-content-type-options' not in response: response["x-content-type-options"] = "nosniff" if self.xss_filter and 'x-xss-protection' not in response: response["x-xss-protection"] = "1; mode=block" return response