Django 学习笔记之 Class-Based-View

来源:互联网 发布:软件开发流程文档 编辑:程序博客网 时间:2024/05/24 01:39

转自:http://www.h3399.cn/201703/59652.html

下面这篇文章主要介绍了 Class-based View,为什么要有这个 Class-based View 呢?view 不都是一个方法吗?跟类有啥关系?其实答案很明显,用类其实是为了抽象,抽象出通用的,将可变的暴露出来,这样我们就可以用最少的代码实现复杂的功能了。下面来看看详细的介绍吧。
Django 是一个开放源代码的 Web 应用框架,由 Python 写成。采用了 MVC 的软件设计模式,即模型 M,视图 V 和控制器 C。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统)软件。并于 2005 年 7 月在 BSD 许可证下发布。这套框架是以比利时的吉普赛爵士吉他手 Django Reinhardt 来命名的。

前言
大家都知道其实学习 Django 非常简单,几乎不用花什么精力就可以入门了。配置一个 url,分给一个函数处理它,返回 response,几乎都没有什么很难理解的地方。
写多了,有些问题才逐渐认识到。比如有一个 view 比较复杂,调用了很多其他的函数。想要把这些函数封装起来,怎么办?当然,可以用注释 #——view—— 这样将函数隔离开,这种方法太 low 了,简直是在骗自己,连封装都算不上。
Python 是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以 Django 在后来加入了 Class-Based-View。可以让我们用类写 View。这样做的优点主要下面两种:
提高了代码的复用性,可以使用面向对象的技术,比如 Mixin(多继承)
可以用不同的函数针对不同的 HTTP 方法处理,而不是通过很多 if 判断,提高代码可读性
使用 class-based views
如果我们要写一个处理 GET 方法的 view,用函数写的话是下面这样。

from django.http import HttpResponsedef my_view(request): if request.method == 'GET':  # <view logic>  return HttpResponse('result')

如果用 class-based view 写的话,就是下面这样。

from django.http import HttpResponsefrom django.views import Viewclass MyView(View): def get(self, request):  # <view logic>  return HttpResponse('result')

Django 的 url 是将一个请求分配给可调用的函数的,而不是一个 class。针对这个问题,class-based view 提供了一个as_view()静态方法(也就是类方法),调用这个方法,会创建一个类的实例,然后通过实例调用dispatch()方法,dispatch()方法会根据 request 的 method 的不同调用相应的方法来处理 request(如get() , post()等)。到这里,这些方法和 function-based view 差不多了,要接收 request,得到一个 response 返回。如果方法没有定义,会抛出 HttpResponseNotAllowed 异常。
在 url 中,就这么写:

# urls.pyfrom django.conf.urls import urlfrom myapp.views import MyViewurlpatterns = [ url(r'^about/$', MyView.as_view()),]

类的属性可以通过两种方法设置,第一种是常见的 Python 的方法,可以被子类覆盖。

from django.http import HttpResponsefrom django.views import Viewclass GreetingView(View): greeting = "Good Day" def get(self, request):  return HttpResponse(self.greeting)
# You can override that in a subclassclass MorningGreetingView(GreetingView): greeting = "Morning to ya"第二种方法,你也可以在 url 中指定类的属性:在 url 中设置类的属性 Pythonurlpatterns = [ url(r'^about/$', GreetingView.as_view(greeting="G'day")),]

使用 Mixin
我觉得要理解 django 的 class-based-view(以下简称 cbv),首先要明白 django 引入 cbv 的目的是什么。在 django1.3 之前,generic view 也就是所谓的通用视图,使用的是 function-based-view(fbv),亦即基于函数的视图。有人认为 fbv 比 cbv 更 pythonic,窃以为不然。python 的一大重要的特性就是面向对象。而 cbv 更能体现 python 的面向对象。cbv 是通过 class 的方式来实现视图方法的。class 相对于 function,更能利用多态的特定,因此更容易从宏观层面上将项目内的比较通用的功能抽象出来。关于多态,不多解释,有兴趣的同学自己 Google。总之可以理解为一个东西具有多种形态(的特性)。cbv 的实现原理通过看 django 的源码就很容易明白,大体就是由 url 路由到这个 cbv 之后,通过 cbv 内部的 dispatch 方法进行分发,将 get 请求分发给 cbv.get 方法处理,将 post 请求分发给 cbv.post 方法处理,其他方法类似。怎么利用多态呢?cbv 里引入了 mixin 的概念。Mixin 就是写好了的一些基础类,然后通过不同的 Mixin 组合成为最终想要的类。
所以,理解 cbv 的基础是,理解 Mixin。Django 中使用 Mixin 来重用代码,一个 View Class 可以继承多个 Mixin,但是只能继承一个 View(包括 View 的子类),推荐把 View 写在最右边,多个 Mixin 写在左边。Mixin 也是比较复杂的技术,本文不详细说了,以后写一篇针对 Mixin 的文章吧。
使用装饰器
在 CBV 中,可以使用 method_decorator 来装饰方法。

from django.contrib.auth.decorators import login_requiredfrom django.utils.decorators import method_decoratorfrom django.views.generic import TemplateViewclass ProtectedView(TemplateView): template_name = 'secret.html' @method_decorator(login_required) def dispatch(self, *args, **kwargs):  return super(ProtectedView, self).dispatch(*args, **kwargs)

也可以写在类上面,传入方法的名字。

@method_decorator(login_required, name='dispatch')class ProtectedView(TemplateView): template_name = 'secret.html'

如果有多个装饰器装饰一个方法,可以写成一个 list。例如,下面这两种写法是等价的。

decorators = [never_cache, login_required]@method_decorator(decorators, name='dispatch')class ProtectedView(TemplateView): template_name = 'secret.html'@method_decorator(never_cache, name='dispatch')@method_decorator(login_required, name='dispatch')class ProtectedView(TemplateView): template_name = 'secret.html'
原创粉丝点击