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加