Django基础CBV装饰器和中间件


Posted in Python onMarch 22, 2022

1. CBV加装饰器

CBV加装饰器有三种方法,

案例:要求登录(不管get请求还是post请求)后才可以访问

HTML代码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <p>Hello Index</p>
</div>
</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <form action="" method="post">
        <p>username:<input type="text" name="username"></p>
        <p>password:<input type="password" name="password"></p>
        <p><input type="submit" value="提交"></p>
    </form>

</div>
</body>
</html>

views.py

# CBV加装饰器方法一:
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
from django.utils.decorators import method_decorator  # django提交加装饰器方法
# Create your views here.
# 装饰器
def login_auth(func):
    def inner(request, *args, **kwargs):
        if request.session.get("is_login"):
            res = func(*args, **kwargs)
            return res
        else:
            return redirect('/login/')
    return inner
class Index(View):
    # 方法一在每个需要验证的地方都加上装饰器
    @method_decorator(login_auth)
    def get(self, request):
        print("get 请求")
        return render(request, "index.html")
	# 个需要验证的地方加上装饰器
	@method_decorator(login_auth)
    def post(self, request):
        print("post 请求")
        return HttpResponse("post")
def login(request):
    if request.method == "POST":
        name = request.POST.get("username")
        password = request.POST.get("password")
        if name == "hans" and password == "123":
            request.session['is_login'] = True
            print("登录成功")
    return render(request, "login.html")
# CBV加装饰器方法二:
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
from django.utils.decorators import method_decorator
# Create your views here.
# 装饰器
def login_auth(func):
    def inner(request, *args, **kwargs):
        if request.session.get("is_login"):
            res = func(*args, **kwargs)
            return res
        else:
            return redirect('/login/')
    return inner
# 方法二 在类的上面加上,name为具体要加的函数
@method_decorator(login_auth, name='post')
@method_decorator(login_auth, name='get')
class Index(View):
    def get(self, request):
        print("get 请求")
        return render(request, "index.html")
    def post(self, request):
        print("post 请求")
        return HttpResponse("post")
def login(request):
    if request.method == "POST":
        name = request.POST.get("username")
        password = request.POST.get("password")
        if name == "hans" and password == "123":
            request.session['is_login'] = True
            print("登录成功")
    return render(request, "login.html")
# CBV加装饰器方法三:
from django.shortcuts import render, HttpResponse, redirect
from django.views import View
from django.utils.decorators import method_decorator
# Create your views here.
# 装饰器
def login_auth(func):
    def inner(request, *args, **kwargs):
        if request.session.get("is_login"):
            res = func(*args, **kwargs)
            return res
        else:
            return redirect('/login/')
    return inner
class Index(View):
    #方法三  使用dispatch给所有的方法添加装饰器
    @method_decorator(login_auth)
    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)
    def get(self, request):
        print("get 请求")
        return render(request, "index.html")
    def post(self, request):
        print("post 请求")
        return HttpResponse("post")
def login(request):
    if request.method == "POST":
        name = request.POST.get("username")
        password = request.POST.get("password")
        if name == "hans" and password == "123":
            request.session['is_login'] = True
            print("登录成功")
    return render(request, "login.html")

urls.py

from django.contrib import admin
from django.urls import path
from wrapperMidd  import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.Index.as_view()),
    path('login/', views.login),
]

访问地址:http://127.0.0.1:8000/index

get的请求使用POSTMAN工具

2. Django中间件

2.1 Django中间件介绍

中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出。

每个中间件组件负责做一些特定的功能,Django中自带了七个中间件

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',   #  安全中间件,为请求/响应周期提供了若干安全增强功能。每一项都可以通过设置独立地启用或禁用。
    'django.contrib.sessions.middleware.SessionMiddleware', # 启用会话支持
    'django.middleware.common.CommonMiddleware', # “通用”中间件
    'django.middleware.csrf.CsrfViewMiddleware', # CSRF 保护中间件,通过在 POST 表单中添加隐藏的表单字段,并检查请求的正确值,增加对跨站点伪造请求的保护。
    'django.contrib.auth.middleware.AuthenticationMiddleware', # 验证中间件,将代表当前登录的用户的 user 属性添加到每个传入的 HttpRequest 对象中
    'django.contrib.messages.middleware.MessageMiddleware', # 消息中间件,启用基于 cookie 和会话的消息支持
    'django.middleware.clickjacking.XFrameOptionsMiddleware', # X-Frame-Options 中间件,简单的 通过 X-Frame-Options 头的点击劫持保护。
]

中间件(Middleware)在整个Djangorequest/response处理机制中的角色如下所示:

HttpRequest -> Middleware(request) -> View -> Middleware(response) -> HttpResponse

中间件常用于权限校验、限制用户请求、打印日志、改变输出内容等多种应用场景.而且中间件对Django的输入或输出的改变是全局的。

Django 中间件作用:

  • 修改请求,即传送到 view 中的 HttpRequest 对象。
  • 修改响应,即 view 返回的 HttpResponse 对象。

中间件执行顺序:

Django基础CBV装饰器和中间件

2.2 自定义中间件

中间件可以定义四个方法:

process_request(self,request)

process_view(self, request, view_func, view_args, view_kwargs)

process_exception(self, request, exception)

process_response(self, request, response)

主要为process_requestprocess_response

2.2.1 自定义中间件

在应用目录下新建一个 py 文件,名字自定义。

在应用目录下创建myMiddle.py
myMiddle.py:
from django.utils.deprecation import MiddlewareMixin
class myMinddle(MiddlewareMixin):
    def process_request(self, request):  # 在视图之前执行
        print("这是自定义中间件 请求1")
    def process_response(self,request, response):  #在视图之后执行
        print("这是自定义中间件 响应1")
        return response

把自定义的中间件注册到setting.py的 MIDDLEWARE里面:

setting.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',
    'wrapperMidd.myMinddle.myMinddle',  # 自定义中间件
]

测试:

views.py:
from django.shortcuts import render, HttpResponse, redirect
def testMinddle(request):
    print("testMinddle")
    return HttpResponse("TEST")
urls.py:
from django.contrib import admin
from django.urls import path
from appName  import views
urlpatterns = [
    path('admin/', admin.site.urls),
    path('testMinddle/', views.testMinddle),
]
# 访问:http://127.0.0.1:8000/testMinddle/
# 结果:
"""
这是自定义中间件 请求1
testMinddle
这是自定义中间件 响应1
"""

增加两个自定义中间件,执行过程:

myMiddle.py:
from django.utils.deprecation import MiddlewareMixin
class myMinddle(MiddlewareMixin):
    def process_request(self, request):
        print("这是自定义中间件 请求1")
    def process_response(self,request, response):
        print("这是自定义中间件 响应1")
        return response
class myMinddle2(MiddlewareMixin):
    def process_request(self, request):
        print("这是自定义中间件 请求2")
    def process_response(self,request, response):
        print("这是自定义中间件 响应2")
        return response
setting.py:
MIDDLEWARE = [
    ......
    'wrapperMidd.myMinddle.myMinddle',
    'wrapperMidd.myMinddle.myMinddle2',
]
# 访问:http://127.0.0.1:8000/testMinddle/
# 结果
"""
这是自定义中间件 请求1
这是自定义中间件 请求2
testMinddle
这是自定义中间件 响应2
这是自定义中间件 响应1
"""

如果在第一个中间件直接返回,执行顺序如果:

myMiddle.py:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class myMinddle(MiddlewareMixin):
    def process_request(self, request):
        print("这是自定义中间件 请求1")
        return HttpResponse("request")   """在这里直接返回"""
    def process_response(self,request, response):
        print("这是自定义中间件 响应1")
        return response
class myMinddle2(MiddlewareMixin):
    def process_request(self, request):
        print("这是自定义中间件 请求2")
    def process_response(self,request, response):
        print("这是自定义中间件 响应2")
        return response
# 访问:http://127.0.0.1:8000/testMinddle/
# 结果:
网页上显示:request
后台显示:
"""
这是自定义中间件 请求1
这是自定义中间件 响应1
"""

2.2.2 自定义中间件总结

自定义中间件先执行process_request再执行views.py里的视图函数,最后再执行process_response,而且process_response函数必须要返回 return response

如果有多个自定义中间件,则执行顺序按settings.py里自上而下执行,写在上面的先执行。执行顺序

自定义中间件1 process_request--->自定义中间件2 process_request-->视图函数-->自定义中间件2 process_response -->自定义中间件1 process_response

如果自定义中间件的process_request里有return返回,而这个中间件还是在上面,则它会执行自己定义的process_requestprocess_response,则视图函数和其他的中间件都不执行

如果自定义中间件的process_request里有return返回,而这个中间件上面还有其他的中间件,则会自上而下执行,执行到自定义中间件的process_request后就会执行process_response,则视图函数和它下面的中间件都不执行

MIDDLEWARE = [
    ...其他中间件...
    '自定义中间件1',
    '自定义中间件2',  #  自定义中间件2里使用return直接返回 
    '自定义中间件3',
]
执行顺序:
"""
其他中间件 process_request  --> 自定义中间件1 process_request --> 自定义中间件2 process_request --> 自定义中间件2 process_response --> 自定义中间件1 process_response -->其他中间件 process_response
"""
视图函数和自定义中间件3是不执行的

2.2.3 其他中间件函数

process_view

process_view在process_request之后,路由转发到视图,执行视图之前执行。
process_view() 只在 Django 调用视图前被调用。它应该返回 None 或 HttpResponse 对象。如果它返回 None ,Django 将继续处理这个请求,执行任何其他的 process_view() ,然后执行相应的视图。如果它返回 HttpResponse 对象,Django 不会去影响调用相应的视图;它会将响应中间件应用到 HttpResponse 并返回结果。
函数定义:
process_view(request, view_func, view_args, view_kwargs)
request 是一个 HttpRequest 对象。
view_func 是一个 Django 将要使用的 Python 函数。(这是一个真实的函数对象,不是函数的名称);view_args 是一个用来传递给视图的位置参数列表,;
view_kwargs 是一个用来传递给视图的关键字参数字典。
view_args 和 view_kwargs 都不包含第一个视图参数 ( request )。

process_exception

视图执行中发生异常时执行。

当视图引发异常时,Django 会调用 process_exception()。process_exception() 应该返回 None 或 HttpResponse 对象。如果它返回一个 HttpResponse 对象,模板响应和响应中间件将被应用且会将结果响应返回浏览器。否则,就会开始默认异常处理( default exception handling )。

再次,中间件在响应阶段会按照相反的顺序运行,其中包括 process_exception 。如果异常中间件返回一个响应,那么中间件之上的中间件类的 process_exception 方法根本不会被调用。

函数定义:
process_exception(request, exception)
request 是一个 HttpRequest 对象。 exception 是一个由视图函数引发的 Exception 对象。

process_template_response

视图函数刚执行完毕,process_response之前执行。

process_template_response() 在视图被完全执行后调用,如果响应实例有 render() 方法,表明它是一个 TemplateResponse 或等效对象。

它必须返回一个实现了 render 方法的响应对象。它可以通过改变``response.template_name`` 和 response.context_data 来改变给定的 response ,或者它可以创建和返回全新的 TemplateResponse 或等效对象。

不需要显式地渲染响应——一旦所有模板中间件被调用,响应会被自动渲染。

中间件会在响应阶段按照相反的顺序运行,其中包括 process_template_response() 。

函数定义:
process_template_response(request, response)

request 是一个 HttpRequest 对象。
response 是 TemplateResponse 对象(或者等效对象),它通过 Django 视图或中间件返回。

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class myMinddle(MiddlewareMixin):
    def process_request(self, request):
        print("这是自定义中间件 请求1")
    def process_response(self,request, response):
        print("这是自定义中间件 响应1")
        return response
    def process_view(self,request, view_func, view_args, view_kwargs):
        print("视图函数之前执行")
    def process_exception(self,request,exception):
        print("处理视图函数")

访问http://127.0.0.1:8000/testMinddle/

结果:

这是自定义中间件 请求1
视图函数之前执行
testMinddle
这是自定义中间件 响应1

视图函数出错示例:

这是自定义中间件 请求1
视图函数之前执行
testMinddle
处理视图函数错误
这是自定义中间件 响应1

2.3 新版本中间件写法

官网上给的示例:

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # 配置和初始化
    def __call__(self, request):
        # 在这里编写视图和后面的中间件被调用之前需要执行的代码,即process_request()
        response = self.get_response(request)
        # 在这里编写视图调用后需要执行的代码,即process_response()
        return response

案例:

使用官网上的写法不用继承 MiddlewareMixin

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.
    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        print("这是自定义中间件 SimpleMiddleware的请求")
        response = self.get_response(request)
        # Code to be executed for each request/response after
        # the view is called.
        print("这是自定义中间件 SimpleMiddleware的响应")
        return response

执行结果:

这是自定义中间件 SimpleMiddleware的请求
testMinddle
这是自定义中间件 SimpleMiddleware的响应

注意

__init__(get_response)

中间件必须接受 get_response 参数。还可以初始化中间件的一些全局状态。记住两个注意事项:

  • Django仅用  参数初始化您的中间件,因此不能定义 __init__() ,因为需要其他参数。
  • 与每次请求都会调用 __call__() 方法不同,当 Web 服务器启动后,__init__() 只被调用一次

上面只定义了process_requestprocess_response 其中process_viewprocess_exception还是要写。

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    def __call__(self, request):
        print("这是自定义中间件 SimpleMiddleware的请求")
        response = self.get_response(request)
        print("这是自定义中间件 SimpleMiddleware的响应")
        return response
    def process_view(self,request, view_func, view_args, view_kwargs):
        print("视图函数之前执行")
    def process_exception(self,request,exception):
        print("处理视图函数错误")

3.Csrf中间件

使用Django框架使用django.middleware.csrf.CsrfViewMiddleware中间件,在前端页面提交操作的时候,会报错:

Forbidden (403)
CSRF verification failed. Request aborted.

解决方法:

如果使用form提交,则在前端页面里加入:

    {% csrf_token %}

如:

<div>
    <form action="" method="post">
     {% csrf_token %}
    <label>username: <input type="text" name="username"></label>
    <label>password:<input type="password" name="password"></label>
    <label><input type="submit" value="提交"></label>
    </form>
</div>

如果是Ajax提交:
"""一定要导入jquery"""
<body>
<div>
    <label>username: <input type="text" name="username" id="user"></label>
    <label>password:<input type="password" name="password" id="pwd"></label>
    <input type="button" value="提交" id="btn">
</div>
<script>
    $('#btn').click(function (){
        $.ajax({
            url: "",
            method: "post",
            data: {username: $('#user').val(), password: $('#pwd').val(), csrfmiddlewaretoken: '{{csrf_token}}'},
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</body>
# 使用cookie:
使用cookie 则要导入"""jquery.cookie.min.js"""
<script src="https://cdn.bootcdn.net/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
const csrftoken = $.cookie('csrftoken');
使用:
<body>
<div>
    <label>username: <input type="text" name="username" id="user"></label>
    <label>password:<input type="password" name="password" id="pwd"></label>
    <input type="button" value="提交" id="btn">
</div>
<script>
    $('#btn').click(function (){
        const csrftoken = $.cookie('csrftoken');
        $.ajax({
            url: "",
            headers:{'X-CSRFToken': csrftoken},  // 加请求头。
            method: "post",
            data: {username: $('#user').val(), password: $('#pwd').val()},
            success: function (data) {
                console.log(data)
            }
        })
    })
</script>
</body>

全局使用csrf局部函数使用,或全局不使用,局部函数使用csrf

from django.views.decorators.csrf import csrf_exempt,csrf_protect
# 全局使用,局部不使用
@csrf_exempt
def xxx()
# 全局不使用(禁用掉),局部使用
@csrf_protect
def yyy()

以上就是Django基础CBV装饰器和中间件的详细内容,更多关于Django基础CBV装饰器和中间件的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python获取android设备的GPS信息脚本分享
Mar 06 Python
关于Python数据结构中字典的心得
Dec 04 Python
Sanic框架请求与响应实例分析
Jul 16 Python
python实现beta分布概率密度函数的方法
Jul 08 Python
利用Python脚本实现自动刷网课
Feb 03 Python
scrapy数据存储在mysql数据库的两种方式(同步和异步)
Feb 18 Python
python新式类和经典类的区别实例分析
Mar 23 Python
python使用PIL剪切和拼接图片
Mar 23 Python
Python小白学习爬虫常用请求报头
Jun 03 Python
Python如何获取文件路径/目录
Sep 22 Python
python 多线程中join()的作用
Oct 29 Python
Python上下文管理器Content Manager
Jun 26 Python
详解pytorch创建tensor函数
Mar 22 #Python
详解Python+OpenCV绘制灰度直方图
PYTHON使用Matplotlib去实现各种条形图的绘制
Python+OpenCV实现在图像上绘制矩形
Matplotlib绘制条形图的方法你知道吗
Python的代理类实现,控制访问和修改属性的权限你都了解吗
Mar 21 #Python
python的netCDF4批量处理NC格式文件的操作方法
You might like
php中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
基于laravel缓冲cache的用法详解
2019/10/23 PHP
用javascript连接access数据库的方法
2006/11/17 Javascript
ext监听事件方法[初级篇]
2008/04/27 Javascript
jquery.lazyload  实现图片延迟加载jquery插件
2010/02/06 Javascript
js 数据类型转换总结笔记
2011/01/17 Javascript
自己写的兼容ie和ff的在线文本编辑器类似ewebeditor
2012/12/12 Javascript
js渐变显示渐变消失示例代码
2013/08/01 Javascript
jQuery使用$.get()方法从服务器文件载入数据实例
2015/03/25 Javascript
JS实现动态生成表格并提交表格数据向后端
2020/11/25 Javascript
jQuery Validate插件实现表单验证
2016/08/19 Javascript
纯javascript版日历控件
2016/11/24 Javascript
史上最全JavaScript常用的简写技巧(推荐)
2017/08/17 Javascript
使用webpack4编译并压缩ES6代码的方法示例
2019/04/24 Javascript
微信小程序云开发修改云数据库中的数据方法
2019/05/18 Javascript
js实现图片上传到服务器和回显
2020/01/19 Javascript
微信小程序学习总结(三)条件、模板、文件引用实例分析
2020/06/04 Javascript
VSCode launch.json配置详细教程
2020/06/18 Javascript
解决vue打包 npm run build-test突然不动了的问题
2020/11/13 Javascript
[14:51]DOTA2 HEROS教学视频教你分分钟做大人-卓尔游侠
2014/06/13 DOTA
python删除列表中重复记录的方法
2015/04/28 Python
Python实现简单的语音识别系统
2017/12/13 Python
Python人脸识别初探
2017/12/21 Python
python保存二维数组到txt文件中的方法
2018/11/15 Python
详解tensorflow之过拟合问题实战
2020/11/01 Python
python中实现栈的三种方法
2020/12/19 Python
Pyecharts 中Geo函数常用参数的用法说明
2021/02/01 Python
详解WebSocket跨域问题解决
2018/08/06 HTML / CSS
介绍一下Make? 为什么使用make
2016/07/31 面试题
《学棋》教后反思
2014/04/14 职场文书
初中差生评语
2014/12/29 职场文书
六一儿童节新闻稿
2015/07/17 职场文书
MySQL时间设置注意事项的深入总结
2021/05/06 MySQL
GoLang中生成UUID唯一标识的实现
2021/05/08 Golang
Android开发之WECHAT微信小程序路由跳转的两种形式
2022/04/12 Java/Android
Python+Pillow+Pytesseract实现验证码识别
2022/05/11 Python