中间件
目录
中间件
中间件介绍
中间件介绍:
用来处理django的请求和响应的框架级别的钩子,是一个轻量,低级的插件系统
用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能
中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法
功能展示:
做一些网站的全局性功能 考虑使用django的中间件
1.全局的用户登录校验
2.全局的用户访问频率校验
3.全局的用户权限校验()
--》全局范围内改变Django的输入和输出
自定义中间件:
django默认的中间键:
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配置列表(列表是有序的)
查看中间件的源码:from django.middleware.csrf import CsrfViewMiddleware
请求流程 :1.请求经过网关接口,同行中间件是从上往下的执行顺序,
2.若其中之一的中间件出错,则请求原路返回(process_requset)
3.通过中间件后,对应中间键执行相应功能,当视图函数执行完毕
4.再一次通过中间件则是从下到上(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定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。
自定义中间件注意事项:
1.自定义中间件需要在MIDDLEWARE内调加自定义中间件的绝对(相对)路径
eg: middeeware.my_middleeware.M1
2.自定义中间件的类需要继承 --MiddlewareMixin
3.自定义中间件本质: 可以修改类内部的五个内置方法!!!
process_request / process_response / process_views /process_exception
process_template_response
process_request
-- processs_request(request)
它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。
from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
def process_request(self,request): # request : 视图函数中的request是一样的
print("MD1里面的 process_request")
class MD2(MiddlewareMixin):
def process_request(self, request):
print("MD2里面的 process_request")
pass
# settings 注册中间件:
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
]
总结:
1.中间件的process_request方法是在执行视图函数之前执行的。
2.当配置多个中间件时,按照MIDDLEWARE中的注册顺序,按照列表的索引值,从前到后依次执行
3.不同中间件之间传递的request都是同一个对象
process_response
-->多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的
-->定义process_response方法时,必须给方法传入两个形参,request和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")
pass
def process_response(self, request, response):
print("MD2里面的 process_response")
return response
总结:
1.process_response方法是在视图函数之后执行的,按照MIDDLEWARE中的注册倒序执行
2.该方法返回什么(HttpResponsed对象) 前端就能获得什么
3.须有两个形参 并且必须返回response形参 不返回直接报错
process_view
-->process_view(self, request, view_func, view_args, view_kwargs)
request是HttpRequest对象。
view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
view_args是将传递给视图的位置参数的列表.
view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含视图参数(request)
返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,那么将不会执行Django的视图函数,而是直接在中间件中掉头,倒叙执行一个个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
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")
pass
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__)
总结 :
process_view方法是在Django路由系统之后,视图系统之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的
process_exceptior
process_exception(self, request, exception)
该方法两个参数:
一个HttpRequest对象
一个exception是视图函数异常产生的Exception对象
只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
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")
pass
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")
总结:
1.视图函数中无异常,process_exception方法不执行。
process_template_response
process_template_response(self, request, response)
一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。
process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)
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")
pass
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
def index(request):
print("app01 中的 index视图")
def render():
print("in index/render")
return HttpResponse("O98K")
rep = HttpResponse("OK")
rep.render = render
return rep
视图函数执行完之后,立即执行了中间件的process_template_response方法,顺序是倒序,先执行MD1的,在执行MD2的,接着执行了视图函数返回的HttpResponse对象的render方法,返回了一个新的HttpResponse对象,接着执行中间件的process_response方法。
中间件版登录验证
---->中间件版的登录验证需要依靠session,所以数据库中要有django_session表。!!
--- 执行同步数据库操作-----
#views.py
from django.shortcuts import render,redirect,HttpResponse
from app02 import models
# Create your views here.
def login(request):
error_msg=''
if request.method=='POST':
username=request.POST.get('username')
password=request.POST.get('password')
user_obj=models.User.objects.filter(username=username,password=password)
if user_obj:
request.session['login']='ok'
#获取用户想直接访问的URL
url=request.GET.get('next')
#跳转到客户初始想访问的URL
if not url:
#没有则默认跳转到home页面
url='/home/'
return redirect(url)
else:
error_msg='username or password error!'
return render(request,'login.html',{'error_msg':error_msg})
def home(request):
return HttpResponse('<h1>这是home页面 只有登录了才能看到</h1>')
def index(request):
return HttpResponse('<h1>这是index页面 也只有登录了才能看到<h1>')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆页面</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<label for="">username:<input type="text" name="username"></label>
<label for="">password:<input type="password" name="password"></label>
<input type="submit" value="submit">
</form>
<h1 style="color: red">{{ error_msg }}</h1>
</body>
</html>
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import redirect
class Check_Login(MiddlewareMixin):
def process_request(self,request):
next_url=request.path_info
if not next_url.startswith('/login/'):
is_login=request.session.get('login','')
if not is_login:
return redirect('/login/?next={}'.format(next_url))
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/',v2.login),
url(r'^home/',v2.home),
url(r'^index/',v2.index)
]
---在MIDDLEWARE内注册中间件 : !!!
MIDDLEWARE = [
'middleware.my_middleware.Check_Login',
]