FBV
FBV ( function base views ) 就是在视图里面使用函数处理请求。
CBV
CBV ( class base views) 就是在视图中使用类处理请求。
Django 加入 CBV 之后我们可以使用类来写 View。这样做的有点是:
- 提高了代码的复用性,可以使用面向对象的技术,例如Mixin(多继承)
- 可以用不同的函数针对不同的 HTTP 方法处理,而不是通过很多的 if 来判断,提高了代码的可读性
使用class-based-views
使用 CBV 写GET 方法:
from django.http import HttpResponse from django.views import View class IndexView(View): def get(self, request): return HttpResponse("ok")
此时配置 url的时候:
# urls.py 文件中 from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.IndexView.as_view()), ] # 其中 views.IndexView.as_view() 中的 .as_view() 是固定写法
Django 的 url 是将一个请求分配给可调用的函数,而不是一个class类。针对这个问题,CBV提供了一个个 as_view() 的静态方法(即类方法),调用这个方法会创建一个类的实例,然后通过实例调用 dispatch() 方法,dispatch() 方法会根据 request 的 method 的不同调用相应的方法来处理 request(如get(),post() 等)。之后又和FBV差不多,要接收 request , 得到一个 response 返回。如果方法没有定义,会抛出 HttpRespondeNotAllowed 异常。
类的属性可以通过两种方法进行设置:
# 第一种方法是常见的 python 方法,可以被子类覆盖。 class IndexView(View): name = 'xm' def get(self, request): return HttpResponse(self.name) # 这种方法也可以被子类覆盖 class ChileIndexView(IndexView): name = 'xh' # 第二种方法是在url中指定类的属性: urlpatterns = [ url(r'^index/$', views.IndexVieew.as_view(name='chenchen')), ]
在使用CBV进行POST请求的时候会被 出现 Forbidden 错误,这是因为在启动 Django 项目的时候会自动进行 csrf 验证。
解决办法:
# 全局解决-----> 即注释掉 csrf 中间件 # 局部解决: # 针对视图函数避免 csrf 验证 from django.views.decorators.csrf import csrf_exempt @ csrf_exempt() def post(self, request): return HttpResponse("POST") # 类方法中: # 方法一: from django.shortcuts import render, HttpResponse from django.views import View from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator @method_decorator(csrf_exempt, name="dispatch") class IndexView(View): def get(self, request, *args, **kwargs): return HttpResponse("OK") def post(self, request, *args, **kwargs): return HttpResponse("POST") # 方法二: from django.shortcuts import render, HttpResponse from django.views import View from django.views.decorators.csrf import csrf_exempt from django.utils.decorators import method_decorator class IndexView(View): @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): print("hello") # 执行父类中的dispatch方法 ret = super(IndexView, self).dispatch(request, *args, **kwargs) print("boy") return ret def get(self, request, *args, **kwargs): return HttpResponse("OK") def post(self, request, *args, **kwargs): return HttpResponse("POST")
使用 Mixin
首先要明白 Django 引入 CBV 的目的:
Python 的一大重要特性就是面向对象。CBV 更能体现 python 的面向对象。CBV 是通过 class 的方式来实现视图方法的。
class 相对于 function 来说,更能利用多态的特点,因此更容易从宏观层面上将项目内比较通用的功能抽象出来,可以理解为一个东西具有多种形态( 的特性 )。CBV 的实现原理大体就是由 url 路由到这个 CBV 之后,通过 CBV 内部的 dispatch 方法进行分发,将 get 请求分发给 cbv.get 方法处理,将 post 请求分发给 cbv.post 方法处理。
在 Django 中使用 Mixin 来重用代码,一个 View Class 可以继承多个Mixin,但是只能继承一个 View(包括View 的子类),推荐把 View 写在最右边,多个 Mixin 写在左边。
Mixin
Mixin
在设计类的继承关系的时候,通常主线都是单一继承下来的。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称为Mixin。
Mixin 的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个 Mixin 的功能,而不是设计多层次的复杂的继承关系。
python 自带的很多库也使用了 Mixin。例如,Python 自带了 TCPServer 和 UDPServer 这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由 ForkingMixin 和 ThreadingMixin 提供。通过组合, 我们就可以创造出合适的服务来。
比如,编写一个多进程模式的 TCP 服务,定义如下:
class MyTCPServer(TCPServer, ForkingMixin): pass
编写一个多线程模式的 UDP 服务,定义如下:
class MyUDPServer(UDPServer, ThreadingMixin): pass
如果想要搞一个更先进的协程模型,可以编写一个 CoroutineMixin:
class MyTCPServer(TCPServer, CoroutineMixin): pass
这样一来,我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类。
小结
由于 Python 允许使用多重继承,因此,Mixin 就是一种常见的设计。只允许单一继承的语言(如java)是不能使用 Mixin 的设计的。