Django通用类视图源码解析

Python中的多继承——MRO

Python支持多继承,这是Python语言的特色之一。

什么是MRO

MRO全称是方法解析顺序(Method Resolution Order)。它定义了Python中多继承存在的情况下,解释器查找函数解析的具体顺序。

什么是函数解析顺序

假如有如下继承关系:
在这里插入图片描述

class A():
    def who_am_i(self):
        print("I am A")


class B(A):
    pass


class C(A):
    def who_am_i(self):
        print("I am C")


class D(B, C):
    pass


d = D()

print(d.who_am_i())

调用的是C中的方法还是A中的方法呢,这就与Python的MRO有关了:

I am C
None

经典类与新式类中MRO

Python的类MRO算法经历了4个阶段:
在这里插入图片描述

经典类的MRO

Python 2按照从左到右的顺序深度优先遍历类的继承图,从而确定类中函数的调用顺序:

  1. 检查当前的类里面是否有该函数,如果有则直接调用。
  2. 检查当前类的第一个父类里面是否有该函数,如果没有则检查父类的第一个父类是否有该函数,以此递归深度遍历。
  3. 如果没有则回溯一层,检查下一个父类里面是否有该函数并按照2中的方式递归。

DFS算法MRO顺序图:
在这里插入图片描述

BFS算法MRO顺序图:
在这里插入图片描述

这两种算法都有自己的弊端,后来引入了C3算法,Python3后更是放弃了DFS算法,只使用C3算法。

新式类的MRO-C3线性化算法

新算法与基于深度遍历的算法类似,但是不同在于新算法会对深度优先遍历得到的搜索路径进行额外的检查。其从左到右扫描得到的搜索路径,对于每一个节点解释器都会判断该节点是不是好的节点。如果不是好的节点,那么将其从当前的搜索路径中移除。

什么是一个好的节点?

N是一个好的节点当且仅当搜索路径中N之后的节点都不继承自N。

如以下继承关系:
在这里插入图片描述

DFS算法得到的继承关系会是:F、A、X、Y、B、Y、X,新式类的MRO从左到右判断出X、Y在后边还会出现就将左边的X、Y移除后就是新式类的继承关系:F、A、B、Y、X

比如Django框架通用类视图中的ListView的继承关系图如下:
在这里插入图片描述

按照新式类的MRO顺序如下:
在这里插入图片描述

通用类视图ListView源码详解

推荐一个查看Django类关系的网站:ccbv.co.uk, 这个网站绝对会给你惊喜。
在这里插入图片描述

先贴一张ListView继承关系图:
在这里插入图片描述

首先要知道Django中的view层相当于java 中的control层,用于处理model和template之间的关系。所以ListView左边的继承关系就是为了处理从Model层中获取数据而封装的一些方法,右边的继承关系是为了处理将获得的数据渲染到template上而封装的方法。

结合MRO关系从上往下看:
在这里插入图片描述

  • view类,所有的类视图函数都继承自view
    在这里插入图片描述

    • as_view():

      将类视图函数转换为视图函数的类方法,url中的类名.as_view()就是使用的这里的方法。

    • dispatch():

      dispatch方法只是验证请求方法是否在合法范围内,重写dispatch方法可以对url请求类视图函数时做些限制:比如自定义一个AuthorRequiredMixin类用于验证是否为原作者,如果不是原作者就抛出权限错误,如果是原作者就正常请求类视图函数:

      class AuthorRequiredMixin(View):
          """
          验证是否为原作者,用于状态删除、文章编辑
          """
          def dispatch(self, request, *args, **kwargs):
              if self.get_object().user.username != self.request.user.username:
                  raise PermissionDenied
              return super(AuthorRequiredMixin, self).dispatch(request, *args, **kwargs)
      

      在需要是原作者的类视图函数中就可以继承上边那个自定义类而达到限制的目的。

  • class ContextMixin:
    在这里插入图片描述

    • get_context_data(self, **kwargs)

      定义一个字典,将需要返回给template的上下文放进去。

  • class MultipleObjectMixin(ContextMixin)

    这个类中的方法是类视图函数中使用比较多的。
    在这里插入图片描述

    • get_queryset()

      查询模型类中的数据返回查询集对象,如果自定义类视图函数中指定了ordering属性,将返回排序后的查询集对象。

      需要注意的是重写这个方法自定义类视图函数必须要指定model属性。
      在这里插入图片描述

    • get_context_data()

      得到视图的上下文,这个方法是重写的父类class ContextMixin中的方法。当我们自定义类视图函数需要增加上下文的时候就可以重写这个方法。
      在这里插入图片描述

      需要注意的是重写这个方法的时候需要注意指定template_name

      class MessageListView(LoginRequiredMixin, ListView):
          """私信列表"""
          model = Message
          template_name = "messager/message_list.html"
      
          def get_context_data(self, *, object_list=None, **kwargs):
              context = super(MessageListView, self).get_context_data()
              # 获取除当前登录用户外的所有用户,按最近登录时间降序排序
              context['users_list'] = get_user_model().objects.filter(is_active=True).exclude(
                  username=self.request.user
              ).order_by('-last_login')[:10]
              # 最近一次私信互动的用户
              last_conversation = Message.objects.get_most_recent_conversation(self.request.user)
              context['active'] = last_conversation.username
              return context
      
          def get_queryset(self):
              """最近私信互动的内容"""
              active_user = Message.objects.get_most_recent_conversation(self.request.user)
              return Message.objects.get_conversation(self.request.user, active_user)
      
  • class BaseListView(MultipleObjectMixin, View)

    一个基类视图,调用class TemplateResponseMixin类中的render_to_response(context)方法将上下文渲染到模板。
    在这里插入图片描述

    我们通过UML图体会到Django框架Mixin类的魅力所在:
    在这里插入图片描述
    在这里插入图片描述

  • class TemplateResponseMixin

    将上下文渲染到模板的mixin类。

    • render_to_response(self, context, **response_kwargs)
      在这里插入图片描述

通用类视图DeleteView源码详解

先看下DeleteView的UML图:
在这里插入图片描述

还是通过MRO的顺序从父类看起:
在这里插入图片描述

  • class View:

    这个类是所有通用类视图都需要继承的类,和ListView继承的View类是同一个,不多说。

  • ContentMixin、TemplateResponseMixin、TemplateView、RedirectView:

    这几个类都在base.py模块中,属于通用类视图共用的模块。
    在这里插入图片描述
    在这里插入图片描述

    因为有共用的模块,所以DeleteViewListView所拥有的属性和方法上有一些共有的,但是也有继承自不同的父类的属性和方法:虽然它们在两个通用类视图中的命名一样但是内容却不一样:
    在这里插入图片描述
    在这里插入图片描述

  • 只要理解了其中一种的通用类视图,在去理解其他的通用类视图只要从继承自不同的父类的方法理解起来就可以了。

    还是通过MRO的顺序从父类看起:

    class SingleObjectMixin(ContextMixin):

    根据定义的pk和slug(url别名)关键字提供检索单个对象以进行进一步操作的能力。
    在这里插入图片描述

    • get_object(self, queryset=None)

      返回查询集过滤后的单个对象。
      在这里插入图片描述

    • get_queryset(self)

      返回查询集对象
      在这里插入图片描述

    • get_context_object_name

      得到上下文对象的名字。
      在这里插入图片描述

    • get_context_data
      在这里插入图片描述

  • BaseDeTailView(SingleObjectMixin, View)
    在这里插入图片描述

    虽然在继承的父类中没有render_to_response()方法,但是render_to_response()方法调用的是TemplateResponseMixin中的方法,利用了Django框架Mixin类的精髓:
    在这里插入图片描述

  • DeletionMixin
    在这里插入图片描述

    继承了DeleteView的自定义类视图中,必须指定success_url,model, 模板名可以使用默认的(就是根据自定义类名获取模板名)比如类名叫做TestDelete,Django框架就会查找名字为test_delete.html的文件,但是最好指定模板名(因为类名变更后和HTML文件名字不一样就会报错) 。
    在这里插入图片描述

通用类视图CreateView源码详解

先看下CreateView的继承关系,CreateView和前边的两个通用类视图相比多了处理表单的类:
在这里插入图片描述

CreateView的MRO顺序如下:
在这里插入图片描述

  • FormMixin(ContextMixin)

    提供一种展示和处理请求中表单的方式。
    在这里插入图片描述

    • get_form

      返回将在视图中使用的表单实例。

      需要注意的是如果自定义类视图中没有定义form_class属性需要重写get_form_class方法:
      在这里插入图片描述
      在这里插入图片描述

  • class ModelFormMixin(FormMixin, SingleObjectMixin)

    提供一种展示和处理请求中模型类表单的方法。
    在这里插入图片描述

    • get_form_class

      该方法返回视图中使用的表单类,但是需要注意的是自定义类视图中不能同时定义form_classfield属性:
      在这里插入图片描述

    • get_form_kwargs

      返回实例化表单后的命名关键字,在自定义通用类视图中可以通过该命名关键字将一些字段加入到表单中:
      在这里插入图片描述
      在这里插入图片描述

    • get_success_url

      返回表单校验成功后需要跳转的url,可以在自定义类视图中定义success_url属性,也可以在model类中定义get_absolute_url字段:
      在这里插入图片描述

    • form_valid

      校验通过后将该表单保存至model类中,并且跳转指定url
      在这里插入图片描述

  • class ProcessFormView(View)

    通过不同的方法来处理表单请求。
    在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一切如来心秘密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值