Django基础CBV装饰器和中间件的应用示例

目录
  • 1. CBV加装饰器
  • 2. Django中间件
    • 2.1 Django中间件介绍
    • 2.2 自定义中间件
    • 2.3 自定义中间件总结
    • 2.4 其他中间件函数
    • 2.5新版本中间件写法
  • 3.Csrf中间件

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 对象。

中间件执行顺序:

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

在应用目录下新建一个 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.3 自定义中间件总结

自定义中间件先执行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.4 其他中间件函数

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.5新版本中间件写法

官网上给的示例:

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装饰器和中间件的资料请关注我们其它相关文章!

(0)

相关推荐

  • Django中的FBV和CBV用法详解

    FBV FBV,即 func base views,函数视图,在视图里使用函数处理请求. 以用户注册代码为例, 使用两个函数完成注册 初级注册代码 def register(request): """返回注册页面""" return render(request, "register.html") def register_handle(request): """进行注册处理""

  • Django中的CBV和FBV示例介绍

    前言 本文主要给大家介绍了关于Django中CBV和FBV的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 一.  CBV CBV是采用面向对象的方法写视图文件. CBV的执行流程: 浏览器向服务器端发送请求,服务器端的urls.py根据请求匹配url,找到要执行的视图类,执行dispatch方法区分出是POST请求还是GET请求,执行views.py对应类中的POST方法或GET方法. 使用实例: urls.py path('login/',views.Login.

  • 详解Django中的FBV和CBV对比分析

    在学习Django过程中在views.py进行逻辑处理时接触到了两种视图的书写风格,FBV和CBV FBV 指 function based views,即基于函数的视图 CBV 指 class based views,即基于类的视图 基于类的视图相较于基于函数的视图可以更加便利的实现类的继承封装等.在日常使用的时候,二者的区别主要在于对于request的请求方法的处理方式 FBV 我们通过函数传入的request的method来判断客户端发起的是什么请求,并进行相应的操作,返回相应的数据. d

  • Django框架CBV装饰器中间件auth模块CSRF跨站请求问题

    CBV添加装饰器 给CBV添加装饰器有三种方法,三种方法都需要导入模块: from django.utils.decorators import method_decorator 第一种直接在方法上面添加: from django.utils.decorators import method_decorator class MyLogin(View): @method_decorator(auth) def get(self, request): return HttpResponse('Is

  • Django CBV类的用法详解

    前言 之前我们在路由匹配的时候,一个url对应一个函数,其实我们还可以一个url对应一个类,这个就是CBV,下面我们来简单的介绍一下CBV 一.CBV的基本用法 1.在路由匹配中要这样写,class_login是对应的类,as_view()是固定写法,必须要这么写,记住后面有个括号 url(r'^class_login/', views.class_login.as_view()), 2.在视图函数中导入一个模块 from django import views 3.在视图函数中写一个类,如果是

  • Django基础CBV装饰器和中间件的应用示例

    目录 1. CBV加装饰器 2. Django中间件 2.1 Django中间件介绍 2.2 自定义中间件 2.3 自定义中间件总结 2.4 其他中间件函数 2.5新版本中间件写法 3.Csrf中间件 1. CBV加装饰器 CBV加装饰器有三种方法, 案例:要求登录(不管get请求还是post请求)后才可以访问 HTML代码 index.html <!DOCTYPE html> <html lang="en"> <head> <meta cha

  • Django基础CBV装饰器和中间件

    目录 1. CBV加装饰器 2. Django中间件 2.1 Django中间件介绍 2.2 自定义中间件 2.2.1 自定义中间件 2.2.2 自定义中间件总结 2.2.3 其他中间件函数 2.3 新版本中间件写法 3.Csrf中间件 1. CBV加装饰器 CBV加装饰器有三种方法, 案例:要求登录(不管get请求还是post请求)后才可以访问 HTML代码 index.html <!DOCTYPE html> <html lang="en"> <hea

  • python基础之装饰器详解

    一.前言 装饰器:本质就是函数,功能是为其他函数添加附加功能 原则: 1.不修改被修饰函数的源代码 2.不修改被修饰函数的调用方式 装饰器 = 高阶函数 + 函数嵌套 + 闭包 二.高阶函数 高阶函数定义: 1.函数接收的参数是一个函数 2.函数的返回值是一个函数名 3.满足上述条件任意一个,都可以称为高阶函数 test 函数是高阶函数,接受了一个foo 作为参数 import time def foo(): time.sleep(3) print("sleep 3s") def te

  • python 使用装饰器并记录log的示例代码

    1.首先定义一个log文件 # -*- coding: utf-8 -*- import os import time import logging import sys log_dir1=os.path.join(os.path.dirname(os.path.dirname(__file__)),"logs") today = time.strftime('%Y%m%d', time.localtime(time.time())) full_path=os.path.join(lo

  • Django中login_required装饰器的深入介绍

    前言 Django提供了多种装饰器, 其中login_required可能是经常会使用到的. 这里介绍下四种使用此装饰器的办法. 当然, 在使用前, 记得在工程目录的settings.py中设置好LOGIN_URL 使用方法 1. URLconf中装饰 from django.contrib.auth.decorators import login_required, permission_required from django.views.generic import TemplateVie

  • Python中使用装饰器来优化尾递归的示例

    尾递归简介 尾递归是函数返回最后一个操作是递归调用,则该函数是尾递归. 递归是线性的比如factorial函数每一次调用都会创建一个新的栈(last-in-first-out)通过不断的压栈,来创建递归, 很容易导致栈的溢出.而尾递归则使用当前栈通过数据覆盖来优化递归函数. 阶乘函数factorial, 通过把计算值传递的方法完成了尾递归.但是python不支出编译器优化尾递归所以当递归多次的话还是会报错(学习用). eg: def factorial(n, x): if n == 0: ret

  • PHP简单装饰器模式实现与用法示例

    本文实例讲述了PHP简单装饰器模式实现与用法.分享给大家供大家参考,具体如下: <?php //装饰器模式-在不改变原有类的结构上,对类的功能那个作补充 //武器基类 abstract class Weapon{ abstract public function descriptions(); abstract public function cost(); } //剑类 class Glave extends Weapon{ public function descriptions(){ re

  • python3 property装饰器实现原理与用法示例

    本文实例讲述了python3 property装饰器实现原理与用法.分享给大家供大家参考,具体如下: 学习python的同学,慢慢的都会接触到装饰器,装饰器在python里是功能强大的语法.装饰器配合python的魔法方法,能实现很多意想不到的功能.废话不多说,如果你已经掌握了闭包的原理,代码的逻辑还是可以看明白的,咱们直接进入正题. property的意义 @property把一个类的getter方法变成属性,如果还有setter方法,就在setter方法前面加上@method.setter.

  • python装饰器实例大详解

    一.作用域 在python中,作用域分为两种:全局作用域和局部作用域. 全局作用域是定义在文件级别的变量,函数名.而局部作用域,则是定义函数内部. 关于作用域,我们要理解两点: a.在全局不能访问到局部定义的变量 b.在局部能够访问到全局定义的变量,但是不能修改全局定义的变量(当然有方法可以修改) 下面我们来看看下面实例: x = 1 def funx(): x = 10 print(x) # 打印出10 funx() print(x) # 打印出1 如果局部没有定义变量x,那么函数内部会从内往

随机推荐