DRF视图的使用及源码流程分析
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()
方法执行父类View
的as_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:
as_view()
是入口,得到view函数- 请求来了调用
view
函数,内部调用dispatch
函数完成请求分发 dispatch
函数将请求方式映射为视图类的同名方法,得到相应结果
APIView:
as_view()
是入口,通过执行父类中的as_view
方法得到view函数,然后在返回view
函数的时候免除csrf验证。- 请求来了调用
view
函数,内部调用(APIView类中的)dispatch
方法完成请求分发。 - 在
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_field
为name
。 - 同时也会检查用户是否有权限查看该对象。
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视图的使用及源码流程分析的更多相关文章
- Flask源码流程分析(一)
Flask源码流程分析: 1.项目启动: 1.实例化Flask对象 1. 重要的加载项: * url_rule_class = Rule * url_map_class = Map * session ...
- 【转】ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
原文地址:http://blog.csdn.net/a396901990/article/details/36475213 简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量—— ...
- ANDROID自定义视图——onMeasure,MeasureSpec源码 流程 思路详解
简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3. ...
- @app.route源码流程分析
@app.route(), 是调用了flask.app.py文件里面的Flask类的route方法,route方法所做的事情和add_url_rule类似,是用来为一个URL注册一个视图函数,但是我们 ...
- Spring事件监听ApplicationListener源码流程分析
spring的事件机制是基于观察者设计模式的,ApplicationListener#onApplicationEvent(Event)方法,用于对事件的处理 .在容器初始化的时候执行注册到容器中的L ...
- u-boot的SPL源码流程分析
上次梳理了一下SPL的基本概念和代码总体思路,这次就针对代码跑的流程做个梳理.SPL中,入口在u-boot-spl.lds中 ENTRY(_start) SECTIONS { .text : { __ ...
- Flask启动原理,源码流程分析
1.执行Flask的实例对象.run()方法 from flask import Flask,request,session app = Flask(__name__) app.secret_key ...
- MyBatis源码流程分析
mybatis核心流程三大阶段 Mybatis的初始化 建造者模式 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提 ...
- requireJS源码流程分析
随机推荐
- Spring bean注册
DefaultListableBeanFactory中: DefaultListableBeanFactory实现了BeanDefinitionRegistry,这个接口的实现完成BeanDefini ...
- How tomcat works(深入剖析tomcat)servlet容器
How tomcat works (5)servlet容器阅读笔记 第四章阅读了tomcat默认连接器的实现,当时connector中的使用的容器是自定义的容器,也是非常之简单奥,一个人就干完了所有的 ...
- 01_Activity生命周期及传递数据
1. Activity的生命周期: 2. Activity启动另一个Activity,并传递数据: package com.example.activitydemo; import android.a ...
- form 表单上传文件及传输数据的编码格式
form中的 action 控制请求往什么地方提交 method 请求方式 如果不写默认是get 请求 如果想传文件 必须要把默认的urlencoded的改成enctype="multi ...
- moviepy音视频开发:音频文件存取类AudioFileClip属性和方法介绍
☞ ░ 前往老猿Python博文目录 ░ 一.概述 AudioFileClip是AudioClip的直接子类,用于从一个音频文件或音频数组中读入音频到内存构建音频剪辑.但AudioFileClip并不 ...
- 第15.30节 PyQt编程实战:通过eventFilter监视QScrollArea的widget()的Paint消息画出scrollAreaWidgetContents的范围矩形
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.引言 在<PyQt(Python+Qt)学习随笔:QScrollArea滚动区域详解> ...
- 学习一下 SpringCloud (一)-- 从单体架构到微服务架构、代码拆分(maven 聚合)
一.架构演变 1.系统架构.集群.分布式系统 简单理解 (1)什么是系统架构? [什么是系统架构?] 系统架构 描述了 在应用程序内部,如何根据 业务.技术.灵活性.可扩展性.可维护性 等因素,将系统 ...
- js已知A,B两点坐标,在线段AB上有C点,已知AC的距离,求C点的坐标
/** * @param {Number} _x1 A点坐标 * @param {Number} _y1 A点坐标 * @param {Number} _x2 B点坐标 * @param {Numbe ...
- 人社部新职业,Panda Global发现区块链新职业榜上有名!
近日,为了助力新冠肺炎疫情的防控,扎实做好"六稳"工作,全面落实"六保"任务,促就业拓岗位,人力资源社会保障部联合市场监管总局.国家统计局近日正式向社会发布一批 ...
- AcWing 232. 守卫者的挑战
题目链接 大型补档计划. 比较显然的dp 设 \(f[i][j][k]\) 为前 \(i\) 次,擂台上了 \(j\) 次,空闲容量(背包 - 使用的)为 \(k\) 的概率. 不上擂台的转移:\(f ...