类视图
1,CBV:类视图
提高了代码的复用性,可以使用面向对象的技术,
可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
Django的url是将一个请求分配给可调用的函数的,而不是一个class。针对这个问题,class-based view提供了一个
as_view()
静态方法(也就是类方法),调用这个方法,会创建一个类的实例,然后通过实例调用dispatch()
方法,dispatch()
方法会根据request的method的不同调用相应的方法来处理request(如get()
,post()
等)。到这里,这些方法和function-based view差不多了,要接收request,得到一个response返回。如果方法没有定义,会抛出HttpResponseNotAllowed异常。-
dispatch方法
所有支持类似CBV的框架,不限开发语言,都是基于反射来实现的,根据method不同来执行不同的请求方法,CBV的关键就是dispatch方法的使用
在Django里面的base.py中,写好了dispatch()来处理请求
url访问的时候,会执行as_view()方法
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.IndexView.as_view()) # 执行类后面的as_view()方法,是父类里面的方法 ]
然后as_view在base.py中的view类里面
这里能看出执行as_view()时返回view会执行view方法,view方法又会调用dispatch方法,返回dispatch方法的返回值
self = cls(**initkwargs)
这里的cls就是请求的类,把这个indexView实例化了
-
这里就是一个修饰器功能
我们可以通过重写dispatch方法来自定义处理请求:
在我们的写的IndexView类里面,重写dispatch()class IndexView(View): def dispatch(self, request, *args, **kwargs): return HttpResponse("dispatch") def get(self,request,*args,**kwargs): return HttpResponse("GET") def post(self,request,*args,**kwargs): return HttpResponse("POST") def put(self,request,*args,**kwargs): return HttpResponse("PUT") def delete(self,request,*args,**kwargs): return HttpResponse("DELET")
根据上面写的代码,因为无论请求是什么都会执行dispatch方法,所以无论请求是什么都会返回“dispatch”,那么我们就可以在自己写的这个dispatch方法中自定义,根据请求类型执行什么操作。
class IndexView(View): def dispatch(self, request, *args, **kwargs): # func = getattr(self,request.method.lower) ret = func(request, *args, **kwargs) return ret def get(self,request,*args,**kwargs): return HttpResponse("GET") def post(self,request,*args,**kwargs): return HttpResponse("POST") def put(self,request,*args,**kwargs): return HttpResponse("PUT") def delete(self,request,*args,**kwargs): return HttpResponse("DELET")
这样就可以根据请求类型,用getattr判断,这里注意返回的request.method是大写的,需要小写。
当然这个dispatch在父类View写好了,不用我们写,这里用于理解源码中的dispatch方法 代码示例
-
- views.py文件
from django.shortcuts import render,HttpResponse # Create your views here. from django.views import View class LoginView(View): """ CBV:class base views,就是视图里使用类处理请求,面向对象的编程 """ def dispatch(self, request, *args, **kwargs): print("请求来了") ret = super(LoginView, self).dispatch(request, *args, **kwargs) print("请求结束") return ret def get(self,request): print("这是get请求") return render(request, "login.html") def post(self): return HttpResponse("登录成功")
- urls.py文件
from wednesday.views import LoginView urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', LoginView.as_view()), ] #######urls.py路由写法 url(r'^login/', views.LoginView.as_view()),
2,FBV:function base views
-
在我们日常学习Django中,都是用的FBV(function base views)方式,就是在视图中用函数处理各种请求。而CBV(class base view)则是通过类来处理请求。
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:- 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
- 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
-
两者区别
-
FBV:FBV就是在url中一个路径对应一个函数
-
在url中
fbv就是在url中一个路径对应一个函数 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index) ]
-
在视图函数中
def index(request): return render(request, 'index.html')
-
-
CBV就是在url中一个路径对应一个类
-
在url中
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.IndexView.as_view()) # 执行类后面的as_view()方法,是父类里面的方法 ]
-
在视图函数中
from django.views import View class IndexView(View): # 以get形式访问会执行get函数,一般情况下获取数据 def get(self, *args, **kwargs): return HttpResponse('666') # 以post形式访问的话会执行post函数,一般情况下发送数据 def post(self, *args, **kwargs): return HttpResponse('999')
-
-
-
特别注意
- CBV定义类的时候必须继承view
- 在写url的时候必须加as_view
- 类里面使用form表单提交的话只有get和post方法
3,视图装饰器
添加装饰器前必须导入from django.utils.decorators import method_decorator
添加装饰器的格式必须为@method_decorator(),括号里面为装饰器的函数名
给类添加是必须声明name
-
注意csrf-token装饰器的特殊性,在CBV模式下它只能加在dispatch上面(后面再说)
下面这是csrf_token的装饰器: @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置csrfToken全局中间件。 @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。 注意:from django.views.decorators.csrf import csrf_exempt,csrf_protect
-
类装饰器的三种方式
-
单一装饰
from django.utils.decorators import method_decorator from django.views import View def wrapper(func): def inner(*args, **kwargs): print("被装饰前") ret = func(*args, **kwargs) print("被装饰后") return ret return inner class LoginView(View): """ CBV:class base views,就是视图里使用类处理请求,面向对象的编程 使用装饰器装饰CBV,Django中提供了method_decorator装饰器 用于将装饰器转换为方法装饰器 """ #第一种方式 @method_decorator(wrapper) def get(self, request): print("这是get请求") return render(request, "login.html") def post(self, request): print(request.POST) return HttpResponse("登录成功")
-
多个函数装饰
from django.utils.decorators import method_decorator from django.views import View def wrapper(func): def inner(*args, **kwargs): print("被装饰前") ret = func(*args, **kwargs) print("被装饰后") return ret return inner class LoginView(View): """ CBV:class base views,就是视图里使用类处理请求,面向对象的编程 使用装饰器装饰CBV,Django中提供了method_decorator装饰器 用于将装饰器转换为方法装饰器 """ #第二种方式,批量对具体的请求处理方法,get,post都会执行装饰器函数 @method_decorator(wrapper) def dispatch(self, request, *args, **kwargs): print("请求来了") ret = super(LoginView, self).dispatch(request, *args, **kwargs) print("请求结束") return ret def get(self, request): print("这是get请求") return render(request, "login.html") def post(self, request): print(request.POST) return HttpResponse("登录成功")
-