Django基础七之CBV装饰器和中间件

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

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.pyMIDDLEWARE里面:

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 自定义中间件总结

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

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

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

  4. 如果自定义中间件的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仅用 get_response 参数初始化您的中间件,因此不能定义 __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装饰器和中间件的更多相关文章

  1. Python基础(七) 闭包与装饰器

    闭包的定义 闭包是嵌套在函数中的函数. 闭包必须是内层函数对外层函数的变量(非全局变量)的引用. 闭包格式: def func(): lst=[] def inner(a): lst.append(a ...

  2. [oldboy-django][2深入django]FBV + CBV + 装饰器

    FBV django CBV & FBV - FBV function basic view a. urls 设置 urls(r'^test.html$', views.test) b. vi ...

  3. django CBV装饰器 自定义django中间件 csrf跨站请求伪造 auth认证模块

    CBV加装饰器 第一种 @method_decorator(装饰器) 加在get上 第二种 @method_decorator(login_auth,name='get') 加在类上 第三种 @met ...

  4. Django CBV装饰器 中间件 auth模块 CSRF跨站请求

    CBV添加装饰器 给CBV添加装饰器有三种方法,三种方法都需要导入模块: from django.utils.decorators import method_decorator 第一种直接在方法上面 ...

  5. Django day15 (一) cbv装饰器 , 中间件

    一: 装饰器 二: 中间件

  6. {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)

    Django基础七之Ajax 本节目录 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) 一 Ajax简介 ...

  7. day 72 Django基础七之Ajax

    Django基础七之Ajax   本节目录 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) 六 同源策略与 ...

  8. day 60 Django基础七之Ajax

      Django基础七之Ajax   本节目录 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) 六 同源策 ...

  9. {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)

    {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)   Django基础七之 ...

随机推荐

  1. TableView 常用技巧与功能详解

    分割线顶格iOS8 UITableview分割线顶格的做法 //iOS8 Cell分割线顶格 if ([_tableView respondsToSelector:@selector(setSepar ...

  2. k8s之资源限制以及探针检查

    k8s之资源限制以及探针检查 一.资源限制 1. 资源限制的使用 当定义Pod时可以选择性地为每个容器设定所需要的资源数量.最常见的可设定资源是CPU和内存大小,以及其他类型的资源. 2. reuqe ...

  3. jenkins插件Publish Over SSH因安全问题下架

    最近用docker新搭建了一个jenkins,安装插件的时候发现publish over ssh找不到了,官方给出的解释是存在安全隐患于2022.01.12暂停分发,官方解释如下:https://ww ...

  4. 基于Java的简单银行管理系统(MVC设计模式)

    项目导航 功能展示 项目描述 项目结构 `data` `service` `utils` `view ` 欠缺与总结 源码下载 功能展示 本系统基于命令台窗口,暂未与图形页面结合.话不多说,先上效果图 ...

  5. 简述keepalived工作原理

    1.Keepalived 定义 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障.一个LVS服务会有2台服务器运行Keepalived,一台为主服务器 ...

  6. 让数据可视化变得简单 – JavaScript 图形库

    作者 | 董叶 公司决策层会围绕着数据来制定相应的策略,数据的重要性与日俱增,政府.金融机构.互联网大厂正在以前所未有的速度收集数据,面对扑面而来的数据,没有抽象.视觉层的帮助,我们很难快速理解掌握其 ...

  7. Redis 中常见的集群部署方案

    Redis 的高可用集群 前言 几种常用的集群方案 主从集群模式 全量同步 增量同步 哨兵机制 什么是哨兵机制 如何保证选主的准确性 如何选主 选举主节点的规则 哨兵进行主节点切换 切片集群 Redi ...

  8. Spring Cloud之微服务注册到Eureka Server集群

    在Spring Cloud之服务注册中心搭建Eureka Server服务注册中⼼ - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)中已经搭建好了Eureka Server集群,本文就利用 ...

  9. win10 VScode配置GCC(MinGW)

    前提 安装 Visual Studio Code 安装 C/C++ 扩展 for VS Code 也可以在vscode的extension界面搜索'c'查找插件安装 获取最新的 Mingw-w64 , ...

  10. kafka3.x原理详解看这篇就够了

    一.概述 (一).kafka的定义 1.定义 1)kafka传统的定义:kafka是一个分布式的基于发布/订阅模式的消息队列,主要用于大数据实时处理领域 2)kafka最新的定义:kafka是一个开源 ...