有朋友反映说对于 Django 的 Class-Based-View(基于类的通用视图)还有不少不明白的地方,所以接下来我会在文章中讲解几个经常使用的具备表明性的基于类的视图用法,并在适当的源码层面下讲解其机理和如何按照咱们的须要拓展它。html
全部的类视图都继承django.views.generic.base.View
类。数据库
这多是最简单的通用类视图。通常在仅仅渲染一个模板时派上用场。可直接在URLconf中使用as_view()
方法,以下所示:django
from django.urls import path from django.views.generic import TemplateView urlpatterns = [ path('about/', TemplateView.as_view(template_name="about.html")), ]
从名字咱们能够对其功能略窥一二,ListView 用于列出一系列 Model 对象集合(好比文章列表)。markdown
在开发一个网站时,咱们经常须要获取存储在数据库中的某个 Model 的列表,好比 Blog 要获取文章(Article)列表以显示到首页,一般咱们都会写以下的视图函数来知足咱们的需求:函数
固然这仅仅是一个最为基本的视图函数的例子,Django 开发者发现,若是项目里有大量的视图都是实现相似于上面这种获取存储在数据库中的某个 Model 的列表的功能的话,会不断地重复书写诸以下面的代码:网站
就是不断地获取 Model 列表而后渲染模板文件,Django 说写多了开发人员就以为无聊了,那咱们何不把这些逻辑抽象出来放到一个类里?因而 Django 帮咱们写好了一个类,专门用于处理上面的状况,这就是 ListView,将上面的视图函数转写成类视图以下:url
首先看看 get_queryset() 方法,它完成的功能和 article_list = Article.objects.all() 这句代码相似,获取某个 Model 的列表(这里是文章列表),其中 article_list 就是 context_object_name 属性值。spa
同时咱们加入了本身的逻辑,即对 article_list 中的各个 article 进行了 markdwon 拓展。假如仅仅只须要获取 article_list ,则甚至能够不用复写 get_queryset 方法,只需指定一个 model 属性,告诉 Django 去获取哪一个 model 的列表就能够了,像这样:3d
第二个复写的方法是 get_context_data() 方法,这个方法是用来给传递到模板文件的上下文对象(context)添加额外的内容的(context 的概念在前面的教程中已有介绍,若是这里不懂的话我再简单解释一下,咱们在模板文件中会使用 {{ }} 这样的标签来包裹模板变量,这些变量哪里来的?就是视图函数经过 context 传递到模板的)。code
咱们这里由于首页须要显示分类信息,所以咱们把 category_list 经过 get_context_data 方法加入了 context 对象,视图函数再帮咱们把 context 传递给模板。return super(IndexView, self).get_context_data(**kwargs) 语句的做用是添加了 category_list 到上下文中,还要把默认的一些上下文变量也返回给视图函数,以便其后续处理。
如今有了 model 列表,context,按照视图函数的逻辑应该是把这些传递给模板了,ListView 经过指定 template_name 属性来指定须要渲染的模板,而 context_object_name 是给 get_queryset 方法返回的 model 列表从新命名的,由于默认返回的 model 列表其名字是 object_list,为了可读性,咱们能够经过 context_object_name 来从新指定,例如咱们这里指定为 article_list。
return render_to_response(‘blog/index.html’,context) 的功能在 ListView 中 Django 已经默认帮咱们作了,翻看其源代码就会知道:
若是你改变渲染模板的一些行为,经过复写 render_to_response 方法便可。
以上方法在类视图调用 as_view() 方法后会被自动调用。
ListView 主要用在获取某个 model 列表中
经过 template_name 属性来指定须要渲染的模板,经过 context_object_name 属性来指定获取的 model 列表的名字,不然只能经过默认的 object_list 获取
复写 get_queryset 方法以增长获取 model 列表的其余逻辑
复写 get_context_data 方法来为上下文对象添加额外的变量以便在模板中访问
前面的 ListView 用于获取某个 model 的列表,获取的是一系列对象,但获取单个mdoel对象也是很常见的,好比 Blog 里点击某篇文章后进入文章的详情页,这里获取的就是点击这篇文章。咱们一般会写以下视图函数:
一样的,若是这种需求多的话,开发人员就须要枯燥而乏味地大量重复写 article = get_object_or_404(Article,pk=article_id) 这样的句子,Django 经过 DetailView 来把这种逻辑抽象出来,把上面的视图函数转成类视图:
model 属性告诉 Django 是获取哪一个 model 对应的单个对象,template_name,context_object_name 属性和 ListView 中是同样的做用,pk_url_kwarg 至关于视图函数中的 article_id 参数(也是URLconf中的id参数),已告诉 Django 获取的是 id 为多少的 model 实例。
get_object() 方法默认状况下获取 id 为pk_url_kwarg 的对象,若是须要在获取过程当中对获取的对象作一些处理,好比对文章作 markdown 拓展,经过复写 get_object 便可实现。
以后的处理就和 ListView 相似了,已经实现了 render_to_response 方法来渲染模板。
以上方法在类视图调用 as_view() 方法后会被自动调用。
DetailView主要用在获取某个 model 的单个对象中
经过 template_name 属性来指定须要渲染的模板,经过 context_object_name 属性来指定获取的 model 对象的名字,不然只能经过默认的 object 获取
复写 get_object 方法以增长获取单个 model 对象的其余逻辑
复写 get_context_data 方法来为上下文对象添加额外的变量以便在模板中访问
经过上面的例子你可能并未体会到使用类的通用视图的好处,毕竟咱们写的基于函数的视图彷佛代码量更短,但这仅仅是由于例子简单而已。
同时别忘了,类是能够被继承的,假如咱们已经写好了一个基于类的通用视图,要对其拓展功能,只需继承本来这个类视图便可,而若是写的是函数呢?拓展性就没有这么灵活,可能须要使用到装饰器等高级技巧,或甚至不得不重复一段代码到新拓展的视图函数中。
但本质上而言,基于类的通用视图依然是一个视图函数,由于最终调用时咱们会经过 genericview.as_view() 方法把类视图转换成通常的视图,url 配置是这样的:
所以,基于类的视图并不是什么新的东西,只是为了方便而对通常的视图另外一种形式的改写而已,理解了通常的视图写法后,经过阅读其官方文档和类视图的源码,很快就能掌握如何写好类视图了。
至此。转载请注明出处。
[参考:Django官方文档 https://docs.djangoproject.com/zh-hans/2.0]