基于类的视图(Class-based view)是Django 1.3引入的新的视图编写方式,用于取代以前基于函数(Function-based)方式。 借助于OO和Python中方便的多重继承特性,基于类的视图可以提供更好的抽象与复用能力。 新的通用视图将更加优雅。
Django的文档较为丰富,但在实际开发中往往仍显得不够,很多时候还是需要深入到源代码当中一探究竟。为此,仔细整理了一下基于类的视图的实现方式。期望对以后的开发能够提供更加清晰、直接的参考。
说明: Django大量应用了多重继承特性。将一些通用的功能性代码拆分混入类(Mixin),需要这些混入类的代码时,只需要将混入类加入到类的继承列表中即可——请注意顺序,左侧的类具有较高权限,将覆盖右侧继承类中的同名函数。为了说明方便,将这些混入类(Mixin)成为"工具类"。
源码组织
所有的视图相关代码,均存放与django/views/generic目录中:
-
base.py 保存视图的抽象类,TemplateView和RedirectView,及工具类TemplateResponseMixin的代码
-
create_update.py 基于函数的通用视图。已标记为deprecated
-
date_based.py 基于函数的日期相关通用视图。已标记为deprecated
-
dates.py 新的基于类的日期相关通用视图。用于取代date_based.py
-
detail.py 基于类的单个对象显示相关的视图和工具类
-
edit.py 基于类的对象编辑相关的视图和工具类
-
list.py 基于类的对象列表显示相关视图和工具类
-
list_detail.py 基于函数的列表、显示函数。已标记为deprecated
-
simply.py 基于函数的工具常用工具试图。已标记为deprecated
从逻辑上来看,源代码被组织为抽象基类,工具类(Mixin),常规(具体)实现和基于模型的实现。
源码分析
抽象类和常用视图(base.py)
这个文件包含视图的顶级抽象类(View),基于模板的工具类(TemplateResponseMixin),模板视图(TemplateView)和重定向视图(RedirectView)。
View及View的执行顺序
View是所有基于类的视图的基类。仅实现了一些基本的方法和必要的检查工作。其中最重要的是dispatch方法。再次方法中,根据HTTP请求中的method参数,调用相应的同名处理函数。这里留下了一个口子,后续的类需要根据自己的情况来填补这个口子最终完成一个视图的处理。
-
属性
-
httpmethodnames 定义所有的Http metho['get','post','put','delete','head','options','trace']。
-
方法
-
init 初始化方法
由URLConf调用。包含将关键字参数存入实例属性等功能。
如果一个视图包含一个实例属性,且在urlpattern中设置了相应的值。将配置的值赋给视图对象的方法就是由URLConf调用init函数时作为参数传入。View.init负责具体的赋值工作。
-
as_view 类方法(classonlymethod)。返回Function-based视图函数对象。返回的视图函数对象("在被调用时")负责实例化视图,调用视图的dispatch方法。
-
dispatch 调度函数。根据Http method调用视图的同名函数
-
httpmethodnot_allowed 返回不被允许的http method处理函数
TemplateResponseMixin
提供使用模版渲染的工具类。template_name参数用于指定模版。希望具备模版功能的视图可以直接继承此工具累计可。不过我们很少直接在自己的视图中继承此工具类,因为Django已经提供了一组有用的视图来减少我们的工作。
TemplateView
基于模版的视图 。需要提供附加数据,可以在继承此视图的子类中,重写getcontextdata方法。常用于诸如"about","copyrights" ,"terms"等基于文本的静态内容。只需设置template_name即可。甚至直接可以在URLConf中直接指定此参数。
如:
1 | url(r'^about/$',TemplateView.as_view(template_name='about.html')) |
RedirectView
重定向视图。可以说这个视图提供了完全的重定向功能。无论是http get、post、delete还是head、options都将重定向到url参数指定的地址。
permanent 属性指定是否返回永久(HTTP 301)重定向信息,否则返回临时重定向(HTTP 302),默认是true.
列表类通用视图(list.py)
此文件包含用于显示数据列表常用的类和工具类。不仅可以方便的用于显示基于模型(Model)的数据列表,也可以用于显示自定义数据列表。
此图中绿色部分属于base.py,引入此图中是为了说明他们之间的关系
MultipleObjectMixin
最主要的核心工具类,主要的算法和接口全部都在这个工具类中实现。
- 属性
allow_empty 默认值True。表示没有数据时显示空列表;否则将会产生一个404错误。
queryset 产生数据的queryset实例或"类queryset"数据列表。
model 关联的模型类。
paginated_by 分页的每页数据项数。默认不起用分页。
contextobjectname 保存到context中的对象名称。默认是$(model)_list。
paginator_class 默认值Paginator。分页处理器。
- 方法
get_queryset 获取用于数据显示的列表对象。可以是类queryset对象。此方法优先选择使用queryset属性。未提供queryset属性时,返回model的默认管理器。如果也没有提供model属性,将会产生ImproperlyConfigured异常。
paginatequeryset 根据需要,将queryset分页。返回(paginator, page, page.objectlist, page.hasotherpages())
getpaginateby 返回每页数据项数。None表示不分页。
get_paginator 返回分页器
getallowempty 参见allow_empty属性说明
getcontextobjectname 参见contextobject_name属性说明
getcontextdata 设置视图的附加属性。通常重写此方法来为视图提供附加数据。 默认设计的视图数据:
'paginator': 分页器, 'page_obj': 页对象, 'is_paginated': 是否进行了分页, 'object_list': 视图的数据
*BaseListView*
视图列表基类。继承自MutipleObjectMixin和View。这是一个抽象类。此函数通过增加get方法来整合View的处理流程和MutipleObjectMixin提供的工具函数。
MultipleObjectTemplateResponseMixin
继承自TemplateResponseMixin,并重写gettemplatenames方法。追加$(applabel)/$(model)list.html作为默认模板。
ListView
本模块功能集大成者。一般都是直接继承此类,并重写MutipleObjectMixin的一些默认属性和/或方法来实现需求。
此类继承自MultipleObjectTemplateResponseMixin和BaseListView。一般来说,只需提供model属性,并编写$(model)list.html即可实现数据列表功能。如需分页可以重写paginatedby属性,指定每页数据项数目。