django rest framework中对于APIView、GenericAPIView、ModelViewSet、mixins扩展类的分析。

APIView

示例

根据实际程序来分析:

urls.py

urlpatterns = [
re_path('users', UserAPIView.as_view())
]

views.py

class UserAPIView(APIView):

    def get(self, request):
users = User.objects.filter().all()
ser = UserSerializer(instance=users, many=True)
return CommonResponse(status=status.HTTP_200_OK, data=ser.data)

源码分析

首先,UserAPIView继承了APIView,而APIView继承了View

原生View里面定义了允许的http访问方式。

urls.py中,UserAPIView.as_view()这条语句其实执行的是APIView中的as_view()方法,而APIView中的as_view()方法执行父类Viewas_view()方法。

APIView中的as_view()

View中的as_view()

其中关键的方法为dispatch方法,根据UserAPIView-->APIView-->View的继承顺序,该方法执行的是APIView中的dispatch方法。看下图。

dispatch方法会获取请求方式,判断是否是http允许的请求方式,如果是的话,则分发执行UserAPIView中对应的同名方法。

其实我们也可以在UserAPIView中自定义dispatch方法,如下:

def dispatch(self, request, *args, **kwargs):
func = getattr(self,request.method.lower())
return func(request,*args,**kwargs)

总结:CBV基于反射实现根据请求方式不同,执行不同的方法。

View与APIView的执行流程

View:

  1. as_view()是入口,得到view函数
  2. 请求来了调用view函数,内部调用dispatch函数完成请求分发
  3. dispatch函数将请求方式映射为视图类的同名方法,得到相应结果

APIView:

  1. as_view()是入口,通过执行父类中的as_view方法得到view函数,然后在返回view函数的时候免除csrf验证。
  2. 请求来了调用view函数,内部调用(APIView类中的)dispatch方法完成请求分发。
  3. dispatch方法中,将会二次封装request,完成三大验证(认证、授权、节流),再将请求方式映射为视图类的同名方法,完成请求的处理。

GenericAPIView

执行流程

首先看看GenericAPIView的源码。

可以看出,GenericAPIView继承了APIView。然后还有几个比较重要的类属性,稍后用到再讲。

再往下看它对外暴露的方法:

其实是比较少的,而且大多是get_xxx之类的方法,也就是说,它的as_view()dispatch等方法,其实都是按照APIView的流程处理的。

重要方法

首先我们看get_queryset(),它的意思是批量查找数据库的数据:

  • 可以看到,queryset属性必须进行赋值,按照继承顺序,我们直接在自己定义的视图类中声明queryset属性并进行赋值。
  • 在if判断中,如果queryset是一个QuerySet对象,就获取全部,得到一个QuerySetDict对象,否则原样返回。

QuerySetDict类型如下:

接下来看get_object(),它的意思是从数据库中获取单个对象:

  • filter_kwargs封装查找条件,get_object_or_404负责在queryset中查找符合条件的对象(object)。
  • 看到这里就发现了,默认查询条件是用pk,也就是说你的url中必须要用pk这个形参名进行分组捕获。否则就需要声明lookup_url_kwarg,如果url中的参数为name,那么lokup_url_kwarg="name",然后进行替换组建filter_kwargs。当然如果你的查询条件不是用的pk,就需要修改lookup_field为字段名,如我不是按照pk进行查询,而是按照name,就修改lookup_fieldname
  • 同时也会检查用户是否有权限查看该对象。check_object_permissions

主要的就是以上两个,get_serializer()会调用get_serializer_class获取序列化类,返回序列化类的执行结果。

示例

class UserAPIView(GenericAPIView):
queryset = User.objects
serializer_class = UserSerializer def get(self, request):
users = self.get_queryset()
ser = self.get_serializer(instance=users, many=True)
return CommonResponse(status=status.HTTP_200_OK, data=ser.data)

mixins扩展类

  • rest_framework.mixins中,有五个扩展类,分别是:

    • ListModelMixin:该类主要负责查询所有记录
    • RetrieveModelMixin:该类主要负责查询单条记录
    • CreateModelMixin:该类主要负责创建记录
    • UpdateModelMixin:该类主要负责对记录做更新操作
    • DestroyModelMixin:该类主要负责删除记录
  • 这五个类都继承于object,是独立的子类。
  • 针对GenericAPIView更高级的封装,配合GenericAPIView使用有奇效。
  • 会自动进行return Response(),所以就不用我们再对返回对象进行包装了。
方法 描述
ListModelMixin list() 查询所有,并返回Response对象
RetrieveModelMixin retrieve() 查询单条,并返回Response对象
CreateModelMixin create() 创建记录,并返回Response对象
UpdateModelMixin update() 更新记录,并返回Response对象
DestroyModelMixin destroy() 删除记录,并返回Response对象

## 示例

class UserAPIView(GenericAPIView, ListModelMixin):
queryset = User.objects
serializer_class = UserSerializer def get(self, request):
return CommonResponse(status=status.HTTP_200_OK, data=self.list(request).data)

ModelViewSet

如果继承所有的mixins类,则视图类就会写的非常冗长,可读性较差。

同时,每次都要在视图中return,那我们会考虑能不能简化这步操作。

首先导入ModelViewSet

from rest_framework.viewsets import ModelViewSet

查看它的源码:

再看GenericViewSet

再看ViewSetMixin

注释的意思是说,它重写了as_view()方法,绑定了http方法与视图函数中的方法,这让它必须接收一个actions参数,actions参数设置为一个字典。

示例

urls.py

urlpatterns = [
re_path('users', UserAPIView.as_view(actions={"get": 'list'}))
]

views.py

class UserAPIView(ModelViewSet):
queryset = User.objects
serializer_class = UserSerializer

generics扩展类

至于generics扩展类,提供了以下几个功能:

功能
CreateAPIView 创建记录
DestroyAPIView 删除记录
UpdateAPIView 更新单条记录
ListAPIView 查询所有记录
RetrieveAPIView 查询单条记录
ListCreateAPIView 创建以及查询所有记录
RetrieveUpdateAPIView 更新以及查询单条记录
RetrieveDestroyAPIView 删除以及查询单条记录
RetrieveUpdateDestroyAPIView 删除、更新、查询单条记录

他们的实现也很简单,以`RetrieveDestroyAPIView`类举例:

由此可见,generics中的扩展类都是结合了mixins扩展类GenericAPIView,并且提供了标准的http方法同名方法,这些方法又都分别执行对应的mixins扩展类中的方法。这和我们mixins扩展类部分中的示例大体一致。

示例

urls.py

urlpatterns = [
re_path('users', UserAPIView.as_view(actions={"get": 'list'}))
]

Views.py

class UserAPIView(ViewSetMixin, ListAPIView):
queryset = User.objects
serializer_class = UserSerializer

注:UserAPIView的as_view方法要接收actions参数,而我们要使用的就是ViewSetMixin中重写的as_view方法,因此为了不和ListAPIView中的as_view产生冲突,继承时要把ViewSetMixin放在前面。

看完上面的内容,下面再看这张图片,希望可以帮助梳理本篇文章的内容:

DRF视图的使用及源码流程分析的更多相关文章

  1. Flask源码流程分析(一)

    Flask源码流程分析: 1.项目启动: 1.实例化Flask对象 1. 重要的加载项: * url_rule_class = Rule * url_map_class = Map * session ...

  2. 【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解

    原文地址:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量—— ...

  3. ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解

    简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3. ...

  4. @app.route源码流程分析

    @app.route(), 是调用了flask.app.py文件里面的Flask类的route方法,route方法所做的事情和add_url_rule类似,是用来为一个URL注册一个视图函数,但是我们 ...

  5. Spring事件监听ApplicationListener源码流程分析

    spring的事件机制是基于观察者设计模式的,ApplicationListener#onApplicationEvent(Event)方法,用于对事件的处理 .在容器初始化的时候执行注册到容器中的L ...

  6. u-boot的SPL源码流程分析

    上次梳理了一下SPL的基本概念和代码总体思路,这次就针对代码跑的流程做个梳理.SPL中,入口在u-boot-spl.lds中 ENTRY(_start) SECTIONS { .text : { __ ...

  7. Flask启动原理,源码流程分析

    1.执行Flask的实例对象.run()方法 from flask import Flask,request,session app = Flask(__name__) app.secret_key ...

  8. MyBatis源码流程分析

    mybatis核心流程三大阶段 Mybatis的初始化  建造者模式 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提 ...

  9. requireJS源码流程分析

随机推荐

  1. SpringIOC循环依赖

    目录 1. 什么是循环依赖 注意: 这⾥不是函数的循环调⽤,是对象的相互依赖关系. 循环调⽤其实就是⼀个死循环,除⾮有终结 条件. 2. 循环依赖处理机制 2.1 演示场景: 2.2 处理机制简图 总 ...

  2. Android的Toolbar(含溢出菜单设置[弹出菜单的使用])的使用PopMenu的样式

    http://blog.csdn.net/yingtian648/article/details/52432438(转载) 1.在Toolbar.xml中设置弹出菜单的风格(app:popupThem ...

  3. Java数据结构(十三)—— 二叉排序树(BST)

    二叉排序树(BST) 需求 给定数列{7,3,10,12,5,1,9},要求能够高效的完成对数据的查询和添加 思路三则 使用数组,缺点:插入和排序速度较慢 链式存储,添加较快,但查找速度慢 使用二叉排 ...

  4. C#设计模式-组合模式(Composite Pattern)

    概念 组合是一种结构型设计模式, 你可以使用它将对象组合成树状结构, 并且能像使用独立对象一样使用它们. 组合模式(Composite Pattern)是将对象组合成树形结构以表示'部分-整体'的层次 ...

  5. Python正则表达式处理中的匹配对象是什么?

    老猿才开始学习正则表达式处理时,对于搜索返回的匹配对象这个名词不是很理解,因此在前阶段<第11.3节 Python正则表达式搜索支持函数search.match.fullmatch.findal ...

  6. B站自动爬取器并制作词云

    效果 词云展示 弹幕展示 爬取弹幕过程 基本步骤 1.寻找视频url 2.构造请求头 3.寻找弹幕地址 4.根据弹幕地址运用正则或xpath爬取 寻找B站视频的url 制作请求头 headers = ...

  7. Jenkins Job间传递参数的一种方法

    场景: Jenkins 中可以建多个Job,一般是主编译Job,多个子Job. 子Job要用主Job中的版本号,编译号. 1)  在主Job里面添加脚本命令: echo set MainVersion ...

  8. LibreOj #539. 「LibreOJ NOIP Round #1」旅游路线

    题目链接 做完这道题,我深知当一个问题复杂度过高的时候,把一些可以分离的操作都分散开,可以大幅度降低复杂度..... 发现无论有多少钱,每到一个点后扩展到的距离被限制在 \(min(C, c[i])\ ...

  9. Acwing 734. 能量石

    贪心(微扰) + dp 这道题还是比较难的,前置知识: 贪心的微扰(邻项交换)证法,例题:国王游戏,耍杂技的牛 01背包 算法1:暴力\(O(T * n! * n)\) 可以\(dfs\)全排列枚举所 ...

  10. 笔记-AHOI2013 差异

    AHOI2013 差异 方法1:SA 先板个后缀数组(带 \(height\) 不带 \(st\) 表),用单调队列递推每个后缀 \(sa_i\) 对答案的贡献,求和,用定值减之. #include ...