CBV加装饰器(session)
要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:
from django.utils.decorators import method_decorator
from django.shortcuts import render,redirect,HttpResponse from django.views import View from django.utils.decorators import method_decorator # Create your views here. def login(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') if username == 'zyl' and password == '123': request.session['name'] = 'zyl' return redirect('/home/') return render(request,'login.html') from functools import wraps def login_auth(func): @wraps(func) def inner(request,*args,**kwargs): if request.session.get('name'): return func(request,*args,**kwargs) return redirect('/login/') return inner # @method_decorator(login_auth,name='get') 第二种 name参数必须指定 class MyHome(View): @method_decorator(login_auth) # 第三种 get和post都会被装饰 def dispatch(self, request, *args, **kwargs): super().dispatch(request,*args,**kwargs) # @method_decorator(login_auth) # 第一种 def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')
urls.py
url(r'^login/', views.login), url(r'^home/', views.MyHome.as_view()),
中间件
当Django处理一个Request的过程是首先通过中间件,然后再通过默认的URL方式进行的。我们可以在Middleware这个地方把所有Request拦截住,用我们自己的方式完成处理以后直接返回Response,
主要用于在全局范围内改变Django的输入和输出
中间件能干嘛?
控制用户访问频率,全局登录校验,用户访问白名单,黑名单等
Django默认的Middleware如下:
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', ]
每一个中间件都有具体的功能。中间件可以定义五个方法。
1.请求来的时候会依次执行每一个中间件里面的process_request方法(如果没有直接通过)
2.响应走的时候会依次执行每一个中间件里面的process_response方法(如果没有直接通过)
分析源码
from django.middleware.security import SecurityMiddleware
同样,我们再查看一个:
from django.middleware.common import CommonMiddleware
再来
from django.middleware.csrf import CsrfViewMiddleware
我们会发现一个相同点,就是都有process_request和process_response,但并不是所有的中间件都有process_request,但是所有的中间件都是由process_response,而且process_response必须要有返回值,process_request没有,如果process_request有返回值的话就不会执行后面的程序了(所以这里可以拦截)
我们从浏览器发出一个请求Request,得到一个响应后的内容HttpResponse,也就是说,每一个请求都是先通过中间件中的process_request函数,这个函数返回None 或者HttpResponse 对象,如果返回前者,继续处理其他中间件,如果返回前者,继续处理其他中间件,如果返回一个HttpResponse,就处理终止,返回到网页上。
中间件不用集成任何类(可以继承object),下面一个中间件大概的样子:
class CommonMiddleware(object): def process_request(self, request): return None def process_response(self, request, response): return response
自定义中间件的方法
中间件一共有五个方法:
process_request(self, request)
process_view(self, request, callback, callback_args, callback_kwargs)
process_template_response()
process_exception(self, request, exception)
process_response(self, request, response)
Request预处理函数:process_request(self,request)
如果返回None,Django继续执行这个request,如果返回的是HttpRsoponse对象,Django不会执行任何除了process_response以外的其他中间件以及相应的view,Django立即返回该HttpResponse
View预处理函数:process_view(self, request, callback, callback_args, callback_kwargs)
这个方法的条用实际在Django执行完request预处理函数并确定待执行的view之后,但在view函数实际执行之前
request:HttpRequest 对象。
callback:Django将调用的处理request的python函数. 这是实际的函数对象本身,
而不是字符串表述的函数名。
args:将传入view的位置参数列表,但不包括request参数(它通常是传入view的第一个参数)。
kwargs:将传入view的关键字参数字典。
process_view() 应当返回None或 HttpResponse 对象。如果返回 None, Django将继续处理这个request ,执行后续的中间件, 然后调用相应的view。
如果返回 HttpResponse 对象,Django 将不再执行任何其它的中间件(不论种类)以及相应的view,Django将立即返回。
Template模板渲染函数:process_template_response()
默认不执行,只有在视图函数的返回结果对象中有render方法才会执行,并把对象的render方法的返回值返回给用户(注意不返回视图函数的return的结果了,而是返回视图函数return值(对象)中render方法的结果)
Exception后处理函数:process_exception(self, request, exception)
这个方法只有在request处理过程中出了问题并且view函数抛出了一个未捕获的异常才会被调用。这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件,或者甚至尝试从错误中自动恢复。
Response 后处理函数:process_response(self, request, response)
这个方法的调用时机在 Django 执行 view 函数并生成 response 之后。
总结:
需要你掌握的:
process_request:请求来的时候从上往下依次执行每一个中间件里面的process_request
process_response :响应走的时候会从下往上依次执行每一个中间件里面的process_response方法
了解:
process_view:路由匹配成功执行视图之前自动触发(从上往下依次执行)
process_exception:当视图函数报错了,自动触发(从下往上依次执行)
process_template_response:视图函数返回的对象有一个render()方法
(或者表明该对象是一个TemplateResponse对象或等价方法)(从下往上依次执行)
自定义中间件方法练习
process_request 和 process_response方法
当用户发起请求的时候会依次经过所有的中间件,这个时候的请求是process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。
上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin。
需要导入:
from django.utils.deprecation import MiddlewareMixin
在 views 中:
def index(request): print("view函数...") return HttpResponse("OK")
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request): print('md1请求') def process_response(self,request,response): print('md1返回') return response class Md2(MiddlewareMixin): def process_request(self,request): print('md2请求') def process_response(self,request,response): print('md2返回') return response
1 from django.utils.deprecation import MiddlewareMixin 2 from django.shortcuts import HttpResponse 3 4 class Md1(MiddlewareMixin): 5 def process_request(self,request): 6 print('md1请求') 7 8 def process_response(self,request,response): 9 print('md1返回') 10 return response 11 12 class Md2(MiddlewareMixin): 13 def process_request(self,request): 14 print('md2请求') 15 return HttpResponse('M2中断d') 16 def process_response(self,request,response): 17 print('md2返回') 18 return response
注意:如果当请求到达请求2的时候直接不符合条件返回,即return HTTPResponse(“Md2中断”),程序将请求直接发给中间件2 返回,然后依次返回到请求者
流程图
process_view 方法
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class Md1(MiddlewareMixin): def process_request(self,request): print('md1请求') def process_response(self,request,response): print('md1返回') return response def process_view(self,request,callback, callback_args, callback_kwargs): print('Md1view') class Md2(MiddlewareMixin): def process_request(self,request): print('md2请求') # return HttpResponse('M2中断d') def process_response(self,request,response): print('md2返回') return response
结果
流程图
CSRF跨站请求伪造
我们之前已经接触过一个csrf相关的中间件了?我们一开始让大家把他注释掉,再提交post请求的时候,就不会被forbidden了,后来学会使用csrf_token之后就不再注释这个中间件了。
简介
django为用户实现防止跨站请求伪造的功能,通过中间件
django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
方式
$.ajaxSetup({ data: {csrfmiddlewaretoken: '{{ csrf_token }}' }, });
<form action="/index3/" method="post"> {# {% csrf_token %}#} <p>username:<input type="text" name="username"></p> <p>money:<input type="text" name="money"></p> <p>others:<input type="text" name="others"></p> <input type="submit"> </form> <button>ajax</button> <script> $('button').click(function () { $.ajax({ url:'', type:'post', data:{'name':'jason','csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val()}, success:function (data) { console.log(data) } }) }) </script>
from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt # 不校验csrf def index1(request): return HttpResponse('ok') @csrf_protect # 校验csrf def index2(request): return HttpResponse('ok')
csrf装饰CBV
from django.utils.decorators import method_decorator # @method_decorator(csrf_exempt,name='post') # 不行 不能给单独某一个视图函数加 @method_decorator(csrf_exempt,name='dispatch') # 可以 class Index3(View): # @method_decorator(csrf_exempt) # 第三种 可以 def dispatch(self, request, *args, **kwargs): super().dispatch(request,*args,**kwargs) def get(self,request): return HttpResponse('get') # @method_decorator(csrf_exempt) # 不行 def post(self,request): return HttpResponse('post')
csrf装饰CBV需要注意(******)
csrf_protect 跟正常的CBV装饰器一样 三种
csrf_exempt 只能有下面两种方式
@method_decorator(csrf_exempt,name='dispatch') # 第一种
class Index3(View):
# @method_decorator(csrf_exempt) # 第二种
def dispatch(self, request, *args, **kwargs):
super().dispatch(request,*args,**kwargs)
其实都是给dispatch加