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 相关文章推荐
Java Web开发过程中登陆模块的验证码的实现方式总结
May 25 Python
Python中的os.path路径模块中的操作方法总结
Jul 07 Python
Python采用Django开发自己的博客系统
Sep 29 Python
django1.8使用表单上传文件的实现方法
Nov 04 Python
Django 如何获取前端发送的头文件详解(推荐)
Aug 15 Python
django 解决manage.py migrate无效的问题
May 27 Python
使用Python快速搭建HTTP服务和文件共享服务的实例讲解
Jun 04 Python
python opencv minAreaRect 生成最小外接矩形的方法
Jul 01 Python
python3.5 cv2 获取视频特定帧生成jpg图片
Aug 28 Python
Python如何使用paramiko模块连接linux
Mar 18 Python
python模拟斗地主发牌
Apr 22 Python
python源码剖析之PyObject详解
May 18 Python
详解pytorch创建tensor函数
Mar 22 #Python
详解Python+OpenCV绘制灰度直方图
PYTHON使用Matplotlib去实现各种条形图的绘制
Python+OpenCV实现在图像上绘制矩形
Matplotlib绘制条形图的方法你知道吗
Python的代理类实现,控制访问和修改属性的权限你都了解吗
Mar 21 #Python
python的netCDF4批量处理NC格式文件的操作方法
You might like
Linux编译升级php的详细方法
2013/11/04 PHP
PHP利用hash冲突漏洞进行DDoS攻击的方法分析
2015/03/26 PHP
关于laravel 数据库迁移中integer类型是无法指定长度的问题
2019/10/09 PHP
jquery蒙版控件实现代码
2010/12/08 Javascript
JavaScript 判断日期格式是否正确的实现代码
2011/07/04 Javascript
JS中eval函数的使用示例
2013/07/21 Javascript
js读写cookie实现一个底部广告浮层效果的两种方法
2013/12/29 Javascript
js限制文本框只能输入数字方法小结
2014/06/16 Javascript
javascript数组去重方法汇总
2015/04/23 Javascript
jquery中实现时间戳与日期相互转换
2016/04/12 Javascript
Angular4 中内置指令的基本用法
2017/07/31 Javascript
vue的全局变量和全局拦截请求器的示例代码
2018/09/13 Javascript
vue中如何去掉空格的方法实现
2018/11/09 Javascript
为什么要使用Vuex的介绍
2019/01/19 Javascript
js异步接口并发数量控制的方法示例
2020/11/22 Javascript
[01:46]2018完美盛典章节片——坚守
2018/12/17 DOTA
Python中optionParser模块的使用方法实例教程
2014/08/29 Python
基于python实现的抓取腾讯视频所有电影的爬虫
2016/04/22 Python
Python模拟自动存取款机的查询、存取款、修改密码等操作
2018/09/02 Python
python添加模块搜索路径和包的导入方法
2019/01/19 Python
在Python中,不用while和for循环遍历列表的实例
2019/02/20 Python
python sorted函数的小练习及解答
2019/09/18 Python
如何基于Python实现电子邮件的发送
2019/12/16 Python
Python IDE环境之 新版Pycharm安装详细教程
2020/03/05 Python
学会python自动收发邮件 代替你问候女友
2020/05/20 Python
html5 音乐播放器 audio 标签使用概述
2013/07/15 HTML / CSS
Mankind西班牙男士护肤品网站:购买皮肤护理、护发和剃须
2017/04/27 全球购物
2014乡镇“三八”国际劳动妇女节活动总结
2014/03/01 职场文书
青年文明号口号
2014/06/17 职场文书
2014年党员个人工作总结
2014/12/02 职场文书
个人创业事迹材料
2014/12/30 职场文书
一年级数学上册复习计划
2015/01/17 职场文书
2015年教学副校长工作总结
2015/07/22 职场文书
结婚主持人致辞
2015/07/28 职场文书
Go 在 MongoDB 中常用查询与修改的操作
2021/05/07 Golang
python 字典和列表嵌套用法详解
2021/06/29 Python