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 相关文章推荐
python3.0 字典key排序
Dec 24 Python
Python 中 Meta Classes详解
Feb 13 Python
python 接口_从协议到抽象基类详解
Aug 24 Python
python实现黑客字幕雨效果
Jun 21 Python
Python 多个图同时在不同窗口显示的实现方法
Jul 07 Python
Python如何筛选序列中的元素的方法实现
Jul 15 Python
python 根据字典的键值进行排序的方法
Jul 24 Python
基于Python实现ComicReaper漫画自动爬取脚本过程解析
Nov 11 Python
python实现梯度法 python最速下降法
Mar 24 Python
Jupyter Notebook 文件默认目录的查看以及更改步骤
Apr 14 Python
使用python实现学生信息管理系统
Feb 25 Python
Python基础之常用库常用方法整理
Apr 30 Python
详解pytorch创建tensor函数
Mar 22 #Python
详解Python+OpenCV绘制灰度直方图
PYTHON使用Matplotlib去实现各种条形图的绘制
Python+OpenCV实现在图像上绘制矩形
Matplotlib绘制条形图的方法你知道吗
Python的代理类实现,控制访问和修改属性的权限你都了解吗
Mar 21 #Python
python的netCDF4批量处理NC格式文件的操作方法
You might like
php数组函数序列之array_unique() - 去除数组中重复的元素值
2011/10/29 PHP
Symfony2联合查询实现方法
2016/03/18 PHP
PHP实现唤起微信支付功能
2019/02/18 PHP
php使用curl模拟多线程实现批处理功能示例
2019/07/25 PHP
jquery tablesorter.js 支持中文表格排序改进
2009/12/09 Javascript
日历查询的算法 如何计算某一天是星期几
2012/12/12 Javascript
js调试系列 控制台命令行API使用方法
2014/06/18 Javascript
JQuery中extend的用法实例分析
2015/02/08 Javascript
jQuery使用hide方法隐藏页面上指定元素的方法
2015/03/30 Javascript
js改变Iframe中Src的方法
2015/05/05 Javascript
jQuery+css实现的切换图片功能代码
2016/01/27 Javascript
Active控件问题小结(附解决办法)
2016/06/09 Javascript
Vue结合原生js实现自定义组件自动生成示例
2017/01/21 Javascript
JavaScript函数表达式详解及实例
2017/05/05 Javascript
vue2.0 常用的 UI 库实例讲解
2017/12/12 Javascript
vue-router的使用方法及含参数的配置方法
2018/11/13 Javascript
详解vue beforeRouteEnter 异步获取数据给实例问题
2019/08/09 Javascript
vue 使用lodash实现对象数组深拷贝操作
2020/09/10 Javascript
pyqt4教程之widget使用示例分享
2014/03/07 Python
理解python多线程(python多线程简明教程)
2014/06/09 Python
python实现删除文件与目录的方法
2014/11/10 Python
python删除过期文件的方法
2015/05/29 Python
PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)的步骤详解
2020/11/02 Python
Monnier Freres中文官网:法国领先的奢侈品配饰在线零售商
2017/11/01 全球购物
巴西婴儿用品商店:Bebe Store
2017/11/23 全球购物
String这个类型的class为何定义成final?
2012/11/13 面试题
如何清空Session
2015/02/23 面试题
会计主管岗位职责范文
2013/11/08 职场文书
自我评价中英文语句
2013/11/30 职场文书
2014年环境整治工作总结
2014/12/10 职场文书
校园广播稿范文
2015/08/19 职场文书
2017公司年会主持人开幕词
2016/03/04 职场文书
python3实现无权最短路径的方法
2021/05/12 Python
python flask框架快速入门
2021/05/14 Python
Pygame Event事件模块的详细示例
2021/11/17 Python
AudioContext 实现音频可视化(web技术分享)
2022/02/24 Javascript