介绍——基于类的视图(class-based view)
刚开始的时候,django只有基于函数的视图(Function-based views)。为了解决开发视图中繁杂的重复代码,基于函数的通用视图( Class-based generic views)出现了,但是不久它的弊端就显示出来:无法扩展、无法定制。基于函数的通用视图的不灵活导致它在现实世界中的应用受限。基于类的通用视图也是出于同样的目的被开发出来,它提供一个工具箱并支持多重继承,随着它的应用,人们发现它的可扩展性和灵活性远超它的小兄弟——基于函数的通用视图。
基于类的通用视图是基于函数的通用视图的质的飞跃,而不仅仅是改进
使用基于类的视图
一般而言,如果要对不同的HTTP请求做出不同的相应的话,function-based views会在单一的函数中采用判断分支的方法,比如:
|
1
2
3
4
5
6
7
8
9
|
from django.http import HttpResponse def my_view(request): if request.method == 'GET': # <view logic> return HttpResponse('result') if request.method == 'POST': # <view logic> return HttpResponse('result') |
而在class-based views中,你可以用不同的类实例的方法来响应不同的HTTP request,如:
|
1
2
3
4
5
6
7
8
9
10
|
from django.http import HttpResponsefrom django.views.generic.base import View class MyView(View): def get(self, request): # <view logic> return HttpResponse('result') def post(self, request): # <view logic> return HttpResponse('result') |
django的URL解析器需要将request和相应的参数传递给一个可调用的函数,而不是一个类。所以class-based view提供一个类方法:as_view()来解决这个问题,as_view()方法让你可以把类当做函数来调用。as_view创建一个类实例,然后调用它的dispatch方法,dispatch分析出request是GET、POST或者其他,然后将request匹配给相应的函数,比如将POST请求匹配给post()函数,如果给函数没有定义的话,将引发HttpResponseNotAllowed错误。
|
1
2
3
4
5
6
7
|
# urls.pyfrom django.conf.urls import patternsfrom myapp.views import MyViewurlpatterns = patterns('', (r'^about/', MyView.as_view()),) |
虽然小型的class-based view并不需要依靠类属性来完成它的工作,但是类属性在很多的基于类的设计中都很有用。设置类属性有两个方法。
第一个方法是标准的python方法:在子类中重写类的属性和方法,比如:
|
1
2
3
4
5
6
7
8
|
from django.http import HttpResponsefrom django.views.generic.base import Viewclass GreetingView(View): greeting = "Good Day" def get(self, request): return HttpResponse(self.greeting) |
你可以在子类中这样重写:
|
1
2
|
class MorningGreetingView(GreetingView): greeting = "Morning to ya" |
第二个方法是在URLconf中将类属性作为参数传递给as_view():
|
1
2
3
|
urlpatterns = patterns('', (r'^about/', GreetingView.as_view(greeting="G'day")),) |
使用mixins
mixin是多重继承的一种,它将父类的行为和属性结合在一起。比如说,在基于类的通用视图中,有一个mixin叫TemplateResponseMinxin,它原本的目的是定义方法render_to_response()。当与基础类View的行为结合时,结果是一个神奇的TemplateView类:它拥有分析request并作出相应匹配的方法(原本定义在View中的行为),也拥有一个接受一个template_name并返回一个TempalteReponse对象的render_to_response()方法(原本定义在 TemplateResponseMixin中的行为)
mixins是在不同的类之间重用代码的出色方法,但是它也带来了一些代价。也许你已经注意到了,如果你滥用这种方法的话,你将会迷失在mixin中,因为在冗长的继承树中,你很难辨清一个子类到底是用来干嘛的。
注意你只能从一个通用视图中继承,就是说,只能有一个父类是从View类继承来的。如果你在多个View类的子类中继承,比如尝试将ProsessFormView和ListView结合,结果将不会是你期待的那样。
用基于类的视图处理表格
一个基于函数的视图在处理表格时,看起来会像这样:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from django.http import HttpResponseRedirectfrom django.shortcuts import renderfrom .forms import MyFormdef myview(request): if request.method == "POST": form = MyForm(request.POST) if form.is_valid(): # <process form cleaned data> return HttpResponseRedirect('/success/') else: form = MyForm(initial={'key': 'value'}) return render(request, 'form_template.html', {'form': form}) |
而相似的基于类的视图会想这样:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
from django.http import HttpResponseRedirectfrom django.shortcuts import renderfrom django.views.generic.base import Viewfrom .forms import MyFormclass MyFormView(View): form_class = MyForm initial = {'key': 'value'} template_name = 'form_template.html' def get(self, request, *args, **kwargs): form = self.form_class(initial=self.initial) return render(request, self.template_name, {'form': form}) def post(self, request, *args, **kwargs): form = self.form_class(request.POST) if form.is_valid(): # <process form cleaned data> return HttpResponseRedirect('/success/') return render(request, self.template_name, {'form': form}) |
虽然只是一个简单的例子,但是你可以看到,你可以通过这样的方式来定制视图。比如通过URLconf配置重写类属性(像form_class),或者重写、继承一个或更多的方法。
装饰基于类的视图
class-based view的扩展并不局限于mixins,你也可以使用装饰器。由于基于类的视图不是函数,使用as_view或者创建子类将会以不同的方式了来装饰他们:
|
1
2
3
4
5
6
7
8
9
|
from django.contrib.auth.decorators import login_required, permission_requiredfrom django.views.generic import TemplateViewfrom .views import VoteViewurlpatterns = patterns('', (r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))), (r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),) |
这是装饰一个实例的方法。如果你想装饰视图的每一个实例,你需要使用另一种方法。
装饰类
为了装饰基于类的视图的每一个实例,你需要装饰这个类本身。你可以将这个装饰器应用于类的dispatch()方法来达到这一目的。
类的方法和独立的方法并不完全一样,所以你不能直接将函数装饰器应用于类方法——你需要先将它转化成一个方法装饰器。method_decorator装饰器将一个函数装饰器转化成一个方法装饰器,这样一来,他就可以应用于实例的方法。例如:
|
1
2
3
4
5
6
7
8
9
10
|
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) |
在这个例子中,每个ProtecedView都将有login保护。
注意,method_decorator将 *args 和 **kwargs传递给被装饰的类方法做参数。如果你的方法不接受这种参数,它将引发TypeError
转载请注明出处
介绍——基于类的视图(class-based view)的更多相关文章
- Django——基于类的视图(class-based view)
刚开始的时候,django只有基于函数的视图(Function-based views).为了解决开发视图中繁杂的重复代码,基于函数的通用视图( Funcation-based generic vie ...
- python测试开发django-rest-framework-62.基于类的视图(APIView和View)
前言 django中编辑视图views.py有两种方式,一种是基于类的实现,另外一种是函数式的实现方式,两种方法都可以用. REST框架提供了一个APIView类,它是Django View类的子类. ...
- django 中基于类的视图
django 视图 分为两种: 1. FBV 基于函数的视图 function based view 2. CBV 基于类的视图 class based ...
- Django笔记&教程 7-1 基于类的视图(Class-based views)介绍
Django 自学笔记兼学习教程第7章第1节--基于类的视图(Class-based views)介绍 点击查看教程总目录 1 介绍 Class-based views (CBVs) are view ...
- django-rest-framework之基于类的视图
前言:上一篇博客中,主要讲的是请求和响应,项目里面views.py中的视图函数都是基于函数的,并且我们介绍了@api_view这个很有用的装饰器.同时,我们还介绍了APIView这个类,但是还没使用它 ...
- Django编写RESTful API(三):基于类的视图
欢迎访问我的个人网站:www.comingnext.cn 前言 在上一篇文章中,主要讲的是请求和响应,项目里面views.py中的视图函数都是基于函数的,并且我们介绍了@api_view这个很有用的装 ...
- Django REST FrameWork中文教程3:基于类的视图
我们也可以使用基于类的视图编写我们的API视图,而不是基于函数的视图.我们将看到这是一个强大的模式,允许我们重用常用功能,并帮助我们保持代码DRY. 使用基于类的视图重写我们的API 我们将首先将根视 ...
- Django 基于类的视图(CBV)执行流程 CBV 源码分析
一.CBV(基于类的视图) 视图是可以调用的,它接受请求并返回响应,这不仅仅是一个函数,Django提供了一些可以用作视图的类的例子,这些允许您通过继承或mixin来构建视图并重用代码. 基本示例 D ...
- Django——基于类的视图源码分析 一
基于类的视图(Class-based view)是Django 1.3引入的新的视图编写方式,用于取代以前基于函数(Function-based)方式. 借助于OO和Python中方便的多重继承特性, ...
随机推荐
- 《JavaScript》split和join
首先了解split和join两个函数 split 根据条件截断字符串,返回数组 //str.split(option,length) 字符串转数组 //option:表示分割依据 //length:用 ...
- Hibernate笔记①--myeclipse制动配置hibernate
Hibernate 是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. Hibernate可以应用在任何使用JD ...
- Leetcode题库——16.最接近的三数之和
@author: ZZQ @software: PyCharm @file: threeSumClosest.py @time: 2018/10/14 20:28 说明:最接近的三数之和. 给定一个包 ...
- The last time the sprint(最后一个冲刺)
经过一两个月的努力,我们终于是做出来了一点东西,从一开始接触这个项目开始,从完全不知道怎么去入手到跌跌碰碰,再到现在可以拿出来一点东西给别人看,我觉得很开心,或许我的这个成品在别人眼中并不算是什么,但 ...
- 用原生JS实现多张图片上传及预览功能(兼容IE8)
最近需要做一个图片上传预览的功能(兼容IE8-11.chrome.firefox等浏览器),网上现有的文件上传组件(如webuploader)总是会遇到一些兼容性问题.于是我参考了一些博文(链接找不到 ...
- Unity控件ScrollView使用问题记录
Unity版本:5.6.2 控件Scroll View由4部分组成,如图: 1.含有Scroll Rect组件的根节点:Scroll View 2.含有Mask组件的节点:Viewport 3.所有内 ...
- 0603团队变化+sprint第二个冲刺
开始一个新的冲刺: 起止:2016.6.1~2016.6.14 按照以下过程进行 ProductBacklog:继续向下细化 Sprint 计划会议:确定此次冲刺要完成的目标 Sprint Backl ...
- 如何获取app的activity
(一) 本机安装appium的环境后,在cmd中输入:adb logcat>D:/log.log (二)真题连接电脑或在虚拟机中启动被测试app (三)直接查看d盘的log.log即可从来里面找 ...
- LR_问题_虚拟用户以进程和线程模式运行的区别
进程方式和线程方式的优缺点: 如果选择按照进程方式运行, 每个用户都将启动一个mmdrv进程,多个mmdrv进程会占用大量内存及其他系统资源,这就限制了可以在任一负载生成器上运行的并发用户数的数量,因 ...
- 使用 Vagrant 打造跨平台开发环境fffff
Vagrant 是一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史. 我们可以通过 Va ...