问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

为什么感觉django里面class based view很难

发布网友 发布时间:2022-04-18 04:35

我来回答

1个回答

热心网友 时间:2022-04-18 06:05

我觉得要理解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。
我们以1.5为例简单讲解一下Mixin。
在python-path/Lib/site-packages/django/view/generic文件夹下,包含了django自带的几个基于类的通用视图。

base.py:
ContextMixin:
提供get_context_data方法,给cbv提供context_data
View:
cbv的基类,提供视图分发等功能
TemplateResponseMixin:
提供渲染模板等功能
TemplateView(TemplateResponseMixin, ContextMixin, View):
从类的构造上就可以看出,这个类是由TemplateResponseMixin,ContextMixin,View三个类共同继承而来的,所以同时具有这三个类的特定,因此,这个类完整的提供了一个cbv应该具有的所有动作(除了处理数据)。

RedirectView(View): 这是View的一个子类,实现的是重定向的功能。

base中已经提供了构成cbv最最基础的几个Mixin,以及cbv的基类View。
以下django又提供了detail,list,edit,dates四个模块,这四个模块分别用来处理detail数据(比如显示日志的某一篇的明细信息),list(比如显示某user的所有日志列表),edit(比如为用户提供新增日志和修改日志的功能),dates(比如显示2014年10月的日志)。想一下,从数据维度上讲,默认的django cbv提供了按照数据维度处理的两个不同的cbv,分别是detail和list。detail显示一个数据对象,list显示数据列表。

下面先分析detail.py:
SimpleObjectMixin(ContextMixin):
这是ContextMixin的一个子类,提供最基础的取回单个对象的功能。
BaseDetailView(SimpleObjectMixin, View):
提供显示单个对象的功能。
SimpleObjectTemplateResponseMixin(TemplateResponseMixin):
这是对TemplateResponseMixin的再次封装,为了实现单个对象的模板显示。
DetailView(SimpleObjectTemplateResponseMixin, BaseDetailView):
这就是完整的detail view了。

从以上类的继承上就可以大致猜出,detail模块中的相关cbv其实是对base中提供的mixin的再度继承。从而实现更精细复杂的功能。

所以剩下几个模块题主完全可以自己分析了。

所以分析完了各个模块提供的功能就完了吗?如果到这里止步,那么还是不了解cbv的好处。上文说过,cbv的一大好处就是多态。因此可以把通用的功能抽象出来做成mixin给其他cbv用。
比如,想实现restful API。最简单的,想实现返回json数据。写一个mixin就好了。

class JSONResponseMixin(object):
"""JSON mixin"""
def render_to_response(self, context):
return self.get_json_response(self.convert_context_to_json(context))

def get_json_response(self, content, **httpresponse_kwargs):
return HttpResponse(content,
content_type='application/json',
**httpresponse_kwargs)

def convert_context_to_json(self, context):
return json.mps(context)

怎么用呢?

class CheckRemindUtilView(JSONResponseMixin, ListView):
"""
Check if there is reminder need to be reminded.
This view should be called every minute.
"""
def get_queryset(self):
start = timezone.now()
end = start + datetime.timedelta(minutes=1)
return Reminder.objects.filter(next_t__gte=start,
next_t__lte=end,
is_valid=True)

def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
if (self.get_paginate_by(self.object_list) is not None
and hasattr(self.object_list, 'exists')):
is_empty = not self.object_list.exists()
else:
is_empty = len(self.object_list) == 0
if is_empty:
ret = {'code': 42, 'msg': 'empty'}
else:
for object_ in self.object_list:
code = exec_remind(object_)
object_.previous_t = object_.next_t
update_reminder(object_)
ret = {'code': code, 'msg': 'reminded.'}
return self.render_to_response(ret)

再从另一个方向举个栗子。比如需要对日志进行用户过滤,用户私有的日志只能用户自己看到,其他人看不到。那么只需要写一个PrivateObjectMixin,然后其他DetailView,ListView继承这个就好了。

class PrivateObjectMixin(object):
''' Filter private object for request.user '''

def filte_private(self, queryset):
'''
Filte private object for authenticated user.
'''
ordering = getattr(self, 'ordering', '-date_created')
if not hasattr(self, 'request'):
return queryset
if not hasattr(self.request, 'user'):
return queryset
if self.request.user.is_authenticated():
queryset = queryset.filter(Q(is_valid=True), Q(is_private=True) &
Q(user__id=self.request.user.id) |
Q(is_private=False))
else:
queryset = queryset.filter(is_valid=True, is_private=False)
try:
result = queryset.order_by(ordering)
except FieldError:
# The model doesnot have an `ordering` field.
return queryset
return result

class NoteListView(PrivateObjectMixin, BaseNoteListView):
''' Show note list. '''

def get_queryset(self):
'''
Get notes.
'''
queryset = Note.objects.all()
return self.filte_private(queryset)

上面这两个例子只是简单的应用而已,完全可以借助多态实现更复杂的cbv。
以下是建议部分:
1,建议翻阅django cbv的源码,自己画个图了解cbv的实现原理,继承流程。
2,自己写几个简单的cbv。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
和面的和是什么读音? win10 应用打不开。全都打不开。 进入win10打不开软件 win10电脑软件都打不开是什么原因win10突然软件都打不开软件是怎么回事... 软件打不开怎么办win10电脑点不开软件最简单办法 请问下,离厦门市岛内的台湾路的国联大厦最近的建设银行和农业银行... 从巴黎都市到建设银行怎么坐公交车,最快需要多久 东莞万江官桥窖离建设银行哪路车最近? 建行七支分行有那些公交车经过 佛山哪里有飞越丛林拓展 哪里的麻辣香锅比较好吃? 减肥吃中药反弹吗? 医生,吃中成药调理会不会反弹 喝中药减肥会不会反弹啊 中药减肥反弹吗? 微信的手势密码在哪里设置 减肥吃中药有副作用吗?会反弹吗? 电脑如何下载同花顺软件 岳姓,女孩,出生于公历2010-07-22 14:55,五行缺火,求大师给起个名字 windows7怎么看是不是I5的处理器 求一女孩名字,姓岳要带有含义的并且好听。谢谢 谁可以告诉我这首歌曲叫什么名字:喜欢你在我身边没有期限...属于我们的每一天都值得被纪念 09年《青年文摘》有一篇叫<世界那么大,我只喜欢你>的文章,谁能帮我弄到原文? 很多年前在青年文摘上看到过一篇叫<我们很相爱>的散文,里面有一首诗开头是愿为你划地为牢...求散文的全文 求感人泪下的散文情书一封 跪求一段表白的散文或诗集。谢谢! 求翻译(中文翻译成英语):世上最幸福的事:就是在喜欢你的每一天里都被你喜欢! 大神!! 以 我会一直爱你 写抒情散文 喜欢你的日子里 痛并快乐着 有没有这类的文章,分享几个 董子健为什么晒孙怡丑照? 喝中药时间久了药效会反弹吗?中药用药几天需要停药几天再用吗? 减肥吃中药易反弹吗? 同花顺收费的好还是免费的好。 中药减肥 会不会反弹 吃中药减肥会反弹吗? 中药可以减肥吗?会不会反弹?药方是什么? 电脑鼠标卡了不会动怎么办 停喝中药,能反弹吗? 吃中药减肥会反弹吗?会有头晕,口干,腹泻的症状吗 中药能不能减肥成功? 会不会反弹? 吃了纯中药瘦身要是不吃了他会反弹吗 减肥中药会不会反弹,吃多久见效 吃中药减肥容易反弹吗? 梦见我家衣柜在搬家是不小心境子打碎了 梦见搬家,是什么意思?? 色粉笔和彩铅笔一样吗有区别吗可以搭配使用吗? 准备找工作不小心把身份证丢了 而且是异地怎么办没什么资料 必须要户口本么? 彩色铅笔也分水溶性和非水溶性的么? 怎么给电脑上备份? 身份证丢了,找工作就成问题了,该怎么办?