永发信息网

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

答案:1  悬赏:60  手机版
解决时间 2021-01-25 20:00
为什么感觉django里面class based view很难
最佳答案
我觉得要理解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.dumps(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。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
飞盛汽车生活会所地址在哪,我要去那里办事
泰国2016年gdp是什么水平
如何公告无主案件的烟草专卖处罚决定书
结婚后单独立户口的问题。
唱歌很难听怎么办?声音好像有点深沉,反正很
扬州市邗江区杨寿镇中心小学地址在什么地方,
使用阿达帕林的注意事项包括A.产生严重的刺激
成语狮象搏兔,皆用全力的意思是什么啊?有知
想买个滚筒洗衣机、纠结牌子、3000左右7公斤
雨、介、心、各加上相同的字, 各组成新字
腾达汽修(金瓯路)地址在什么地方,想过去办事
中国石油阳西城西加油站地址好找么,我有些事
一片矩形小树林,长是宽的3倍,而对角线的长为
帮我看看那里错了getClass().getClassLoader(
一个男生的手机壁纸是一个女生的照片。那这个
推荐资讯
我国有许多对联表达了人们对历史名人的深切缅
雷柏7100无线鼠标用不了,电池和电脑都是好的
关于土地规划到和距离征收时间
绵阳站的火车票可以在江油取票么?在哪里可以
昆虫的体表覆盖着保护和支持内部的柔软器官,
求1加根号x分之dx的不定积分
【科8】魏晋南北朝时期把文体分为四科八种和
什么截图软件可以一边玩游戏一边截图
倩女幽魂中月卡冲三十和直接冲三十的区别
什么是等价命题
成语发凡起例的意思是什么啊?有知道释义的请
魔兽世界naxx格拉斯怎么打啊(25人)
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?