1. CBV加装饰器
CBV
加装饰器有三种方法,
案例:要求登录(不管get请求还是post请求)后才可以访问
HTML代码
index.html
1
2
3
4
5
6
7
8
9
10
11
12
|
<!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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<!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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# 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
1
2
3
4
5
6
7
8
|
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
中自带了七个中间件
1
2
3
4
5
6
7
8
9
|
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
)在整个Django
的request/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_request
和process_response
在应用目录下新建一个 py 文件,名字自定义。
1
2
3
4
5
6
7
8
9
|
在应用目录下创建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
里面:
1
2
3
4
5
6
7
8
9
10
11
|
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' , # 自定义中间件 ] |
测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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 """ |
增加两个自定义中间件,执行过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
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 """ |
如果在第一个中间件直接返回,执行顺序如果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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_request
和process_response
,则视图函数和其他的中间件都不执行
如果自定义中间件的process_request
里有return
返回,而这个中间件上面还有其他的中间件,则会自上而下执行,执行到自定义中间件的process_request
后就会执行process_response
,则视图函数和它下面的中间件都不执行
1
2
3
4
5
6
7
8
9
10
11
|
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 视图或中间件返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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新版本中间件写法
官网上给的示例:
1
2
3
4
5
6
7
8
9
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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_request
和process_response
其中process_view
和process_exception
还是要写。
1
2
3
4
5
6
7
8
9
10
11
12
|
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
中间件,在前端页面提交操作的时候,会报错:
1
2
|
Forbidden (403) CSRF verification failed. Request aborted. |
解决方法:
如果使用form提交,则在前端页面里加入:
{% csrf_token %}
如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
< 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
1
2
3
4
5
6
7
|
from django.views.decorators.csrf import csrf_exempt,csrf_protect # 全局使用,局部不使用 @csrf_exempt def xxx() # 全局不使用(禁用掉),局部使用 @csrf_protect def yyy() |
以上就是Django基础CBV装饰器和中间件的详细内容,更多关于Django基础CBV装饰器和中间件的资料请关注服务器之家其它相关文章!
原文链接:https://www.cnblogs.com/hans-python/p/16037470.html