Django之中间件

一.CBV加装饰器

  第一种  @method_decorator(装饰器)  加在get上

  第二种  @method_decorator(login_auth,name='get')  加在类上

  第三种  @method_decorator(login_auth)  加在dispatch上  3.7版本要return super().dispatch
from django.utils.decorators import method_decorator


@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')

二.中间件:

      1. 首先,什么是中间件?

django请求生命周期完整版,中间件类似于django的门卫,数据在进入和离开时都需要经过中间件

     2. 中间件能干嘛?

控制用户访问频率,全局登陆校验,用户访问白名单,黑名单等

     3. Django默认有七个中间件,但是django暴露给用户可以自定义中间件并且里面可以写五种方法

中间件可以定义五个方法,分别是:(主要的是process_request和process_response)
有response需要加上return

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)

  首先查看settings.py中的七个中间件,然后仿照继承中间件的一个类,从而自定义两个中间件,新创建一个文件夹和文件:

from django.utils.deprecation import MiddlewareMixin



class MyMiddleWare(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义的中间件中process_request方法')


    def process_response(self,request,response):
        print('我是第一个自定义的中间件中process_response方法')
        return response
class MyMiddleWare1(MiddlewareMixin):
    def process_request(self,request):
        print('我是第二个自定义的中间件中process_request方法')


    def process_response(self,request,response):
        print('我是第二个自定义的中间件中process_response方法')
        return response

   然后把路径添加在中间件目录的后面:

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',
    'mymiddleware.middleware.MyMiddleWare',
    'mymiddleware.middleware.MyMiddleWare1'
]

视图函数:

def index(request):
    print('我是视图函数')
    return HttpResponse('我是视图函数')

执行顺序:

我是第一个自定义的中间件中process_request方法
我是第二个自定义的中间件中process_request方法
我是视图函数
我是第二个自定义的中间件中process_response方法
我是第一个自定义的中间件中process_response方法

如果process_request返回值是None,程序会继续执行,如果是一个HttpResponse对象(三剑客),程序会在同级掉头,

不会走下一个中间件,更不会走视图函数:

class MyMiddleWare(MiddlewareMixin):
    def process_request(self,request):
        print('我是第一个自定义的中间件中process_request方法')
        return HttpResponse('我是第一个中间件里面返回的对象')
       # return render(request, 'index.html')  同理

执行到这个中间件就回头了:

我是第一个自定义的中间件中process_request方法
我是第一个自定义的中间件中process_response方法

process_view方法:路由匹配成功执行视图函数之前会走这个方法

    def process_view(self, request, view_func, view_args, view_kwargs):
        print('我是第一个自定义的中间件中process_view方法')
        print(view_func.__name__)

 执行顺序:

我是第一个自定义的中间件中process_request方法
我是第二个自定义的中间件中process_request方法
我是第一个自定义的中间件中process_view方法
index
我是第二个自定义的中间件中process_view方法
index
我是视图函数
我是第二个自定义的中间件中process_response方法
我是第一个自定义的中间件中process_response方法
process_exception方法:异常捕获,顺序从下往上
    def process_exception(self, request, exception):
        print("我是第一个自定义的中间件中process_exception方法",exception)
process_template_response方法:顺序也是从下往上
def process_template_response(self, request, response):
print('我是第一个自定义的中间件中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

 流程图:

 如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。

假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

中间件版登陆验证:
urls.py

from app02 import views as v2
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/',v2.login),
    url(r'^home/',v2.home),
    url(r'^index/',v2.index)
]
----------------------------------------------------------------------------
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:
            #设置session
            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>')
----------------------------------------------------------------------------
login.html

<!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>

----------------------------------------------------------------------------
middlewares.py

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))


----------------------------------------------------------------------------
在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',
    'middleware.my_middleware.Check_Login',

]

Django请求流程图:

 

 

posted @ 2019-06-20 17:21  纵横捭阖行  阅读(203)  评论(0编辑  收藏  举报