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中使用Boolean操作符做真值测试实例
Jan 30 Python
python将文本转换成图片输出的方法
Apr 28 Python
Python性能提升之延迟初始化
Dec 04 Python
windows下python安装paramiko模块和pycrypto模块(简单三步)
Jul 06 Python
DataFrame 将某列数据转为数组的方法
Apr 13 Python
python3+PyQt5实现自定义窗口部件Counters
Apr 20 Python
详解Python3.6安装psutil模块和功能简介
May 30 Python
python破解zip加密文件的方法
May 31 Python
pycharm打开命令行或Terminal的方法
Jan 16 Python
利用pyecharts实现地图可视化的例子
Aug 12 Python
Python自动化完成tb喵币任务的操作方法
Oct 30 Python
python实现三壶谜题的示例详解
Nov 02 Python
详解pytorch创建tensor函数
Mar 22 #Python
详解Python+OpenCV绘制灰度直方图
PYTHON使用Matplotlib去实现各种条形图的绘制
Python+OpenCV实现在图像上绘制矩形
Matplotlib绘制条形图的方法你知道吗
Python的代理类实现,控制访问和修改属性的权限你都了解吗
Mar 21 #Python
python的netCDF4批量处理NC格式文件的操作方法
You might like
PHP5新特性: 更加面向对象化的PHP
2006/11/18 PHP
mysql From_unixtime及UNIX_TIMESTAMP及DATE_FORMAT日期函数
2010/03/21 PHP
php 计划任务 检测用户连接状态
2012/03/29 PHP
仿Aspnetpager的一个PHP分页类代码 附源码下载
2012/10/08 PHP
php中HTTP_REFERER函数用法实例
2014/11/21 PHP
PHP易混淆函数的区别及用法汇总
2014/11/22 PHP
php实现用于删除整个目录的递归函数
2015/03/16 PHP
使用PHP生成二维码的方法汇总
2015/07/22 PHP
简单了解WordPress开发中update_option()函数的用法
2016/01/11 PHP
老生常谈PHP面向对象之命令模式(必看篇)
2017/05/24 PHP
firefox和IE系列的相关区别整理 以备后用
2009/12/28 Javascript
jQuery+ajax实现顶一下,踩一下效果
2010/07/17 Javascript
jquery统计输入文字的个数并对其进行判断
2014/01/07 Javascript
Javascript和Java获取各种form表单信息的简单实例
2014/02/14 Javascript
js图片实时加载提供网页打开速度
2014/09/11 Javascript
JavaScript获取DOM元素的11种方法总结
2015/04/25 Javascript
setTimeout内不支持jquery的选择器的解决方案
2015/04/28 Javascript
JavaScript事件委托实例分析
2015/05/26 Javascript
jQuery实现鼠标悬停背景翻转的黑色导航菜单代码
2015/09/14 Javascript
深入浅析AngularJS中的module(模块)
2016/01/04 Javascript
JS字符串的切分用法实例
2016/02/22 Javascript
jquery form表单获取内容以及绑定数据
2016/02/24 Javascript
jquery 多个radio的click事件实例
2016/12/03 Javascript
基于Vue过渡状态实例讲解
2017/09/14 Javascript
微信小程序列表中item左滑删除功能
2018/11/07 Javascript
使用VueCli3+TypeScript+Vuex一步步构建todoList的方法
2019/07/25 Javascript
JS中比较两个Object数组是否相等方法实例
2019/11/11 Javascript
tensorflow实现逻辑回归模型
2018/09/08 Python
python通过对字典的排序,对json字段进行排序的实例
2020/02/27 Python
scrapy结合selenium解析动态页面的实现
2020/09/28 Python
CSS3只让背景图片旋转180度的实现示例
2021/03/09 HTML / CSS
意大利香水和彩妆护肤品购物网站:Ditano
2017/08/13 全球购物
世嘉游戏英国官方商店:SEGA Shop UK
2019/09/20 全球购物
C#的几个面试问题
2016/05/22 面试题
教学实习自我评价
2014/01/28 职场文书
Hive HQL支持2种查询语句风格
2022/06/25 数据库