drf 视图源码详解
mixin类和Generic类
导入
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin, ListModelMixin, UpdateModelMixin, DestroyModelMixin
from rest_framework.generics import GenericAPIView
CreateModelMixin 创建
源码路径为 rest_framework —> mixing.py —>CreateModelMixin
class CreateModelMixin(object):
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
# 传入前端传入的数据,进行反序列化
serializer = self.get_serializer(data=request.data)
# 判断是否全部都校验通过 通过了就执行下面语句
# raise_exception=True 不通过直接报错,下面也不会执行
serializer.is_valid(raise_exception=True)
# 执行perform_create 实际就是.save() 保存
self.perform_create(serializer)
# 头部信息忽略
headers = self.get_success_headers(serializer.data)
# 遵循规范返回创建对象的数据
# status 状态信息,对应的是一个个状态码
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
视图使用-post
class PublishView(CreateModelMixin,GenericAPIView):
queryset = models.Publish.objects.all()
# 内部执行的时候CreateModelMixin调用了serializer_class
serializer_class = PublishSerializers
# 执行post请求就说明要添加数据
def post(self, request, *args, **kwargs):
# 执行create 自己没有就执行CreateModelMixin
# 也就是上面的CreateModelMixin源码解析
return self.create(request, *args, **kwargs)
ListModelMixin - 查看多条数据
源码路径为 rest_framework —> mixing.py —>ListModelMixin
class ListModelMixin(object):
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
# 过滤相关
# 这个时候调用了GenericAPIView内的get_queryset
queryset = self.filter_queryset(self.get_queryset())
# 分页相关
page = self.paginate_queryset(queryset)
# page不为空的情况下
if page is not None:
# 序列化多条
serializer = self.get_serializer(page, many=True)
# 返回序列化的数据
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
视图-get-取所有数据
class PublishView(ListModelMixin,GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
RetrieveModelMixin 获取单条数据
源码路径为 rest_framework —> mixing.py—>RetrieveModelMixin
class RetrieveModelMixin(object):
def retrieve(self, request, *args, **kwargs):
# 获取单条
instance = self.get_object()
# 获取到序列化返回
serializer = self.get_serializer(instance)
return Response(serializer.data)
视图-get-取指定数据
class PublishDetailView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
# 获取指定一条
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
UpdateModelMixin 更新单条数据
源码路径为 rest_framework —> mixing.py—>UpdateModelMixin
class UpdateModelMixin(object):
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
# 要序列化单条数据
instance = self.get_object()
# 序列化
serializer = self.get_serializer(instance, data=request.data, partial=partial)
# 校验是否全部通过
serializer.is_valid(raise_exception=True)
# 直接保存
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
视图 - put- 更新指定数据
class PublishDetailView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
# 更新指定数据
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
DestroyModelMixin - 删除指定数据
class DestroyModelMixin(object):
def destroy(self, request, *args, **kwargs):
# 获取要删除的数据
instance = self.get_object()
# 直接执行删除
self.perform_destroy(instance)
# 返回信息
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
视图 - delete- 删除指定数据
class PublishDetailView(RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView):
queryset = models.Publish.objects.all()
serializer_class = PublishSerializers
# 删除指定数据
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
GenericAPIView 通用的apiview
get_queryset(self):
def get_queryset(self):
assert self.queryset is not None, (
"'%s' should either include a `queryset` attribute, "
"or override the `get_queryset()` method."
% self.__class__.__name__
)
# 这个时候的queryset 是传递进来的queryset对象
queryset = self.queryset
# 判断是否是QuerySet,不是QuerySet 自动.all()
# 说明queryset可以直接给它传递一个对象如 models.Publish.objects
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
# 返回queryset对象
return queryset
generics 里面组合了mixins里面方法和GenericAPIView
导入
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
url
url(r'^publish/$', views.publishView.as_view()),
url(r'^publish/(?P<pk>\d+)/$', views.PublishDetailView.as_view())
ListCreateAPIView源码 创建与查询多条
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericAPIView):
# 获取多条
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
# 创建数据
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
RetrieveUpdateDestroyAPIView源码 查询单条 更新 删除
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
# 获取指定数据
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
# 更新全部
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
# 局部更新
def patch(self, request, *args, **kwargs):
return self.partial_update(request, *args, **kwargs)
# 删除
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
视图
from rest_framework.generics import ListCreateAPIView,RetrieveUpdateDestroyAPIView
class publishView(ListCreateAPIView):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers
class PublishDetailView(RetrieveUpdateDestroyAPIView):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers
ModelViewSet 多种请求映射
导入:
from rest_framework.viewsets import ModelViewSet
- 路由:
url(r'^publish/$', views.PublishView.as_view({'get':'list','post':'create'})),
url(r'^publish/(?P<pk>\d+)/$', views.PublishView.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
- 视图:
from rest_framework.viewsets import ModelViewSet
class PublishView(ModelViewSet):
queryset=models.Publish.objects.all()
serializer_class=PublishSerializers
# 这里面虽然可以满足方法的请求但是有时候我们会更具业务的需要,去修改,我们可以重写指定的方法,如create等
为什么可以可以做到请求映射?
- 主要是重写了as_view方法
1.ModelViewSet中唯一不通的就是继承了GenericViewSet,上面的方法中继承的是GenericAPIView 俩者不同
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
2.GenericViewSet中pass??,继承了之前的GenericAPIView,但是多继承了一个ViewSetMixin
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass
3.ViewSetMixin中仔细看as_view 和原生的Django.views.View.as_view的区别,多了一个参数
Django.views.View.as_view
def as_view(cls, **initkwargs):
pass
ViewSetMixin.as_view
def as_view(cls, actions=None, **initkwargs):
pass
4.所以路由中配置的字典{'get': 'list', 'post': 'create'}给了actions
url(r'^publish/$', views.PublishView.as_view({'get': 'list', 'post': 'create'})),
url(r'^publish/(?P<pk>\d+)/$',
views.PublishView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
5.ViewSetMixin.as_view 源码中如果可以看出如果继承了ViewSetMixin没有传递actions直接就会异常
if not actions:
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`")
6.ViewSetMixin.as_view核心代码,也就是这一段代码让我们的请求直接执行对应的执行函数
def view(request, *args, **kwargs):
self = cls(**initkwargs)
# 调用了传入的actions 赋值给了action_map
self.action_map = actions
# {'get': 'list', 'post': 'create'}
# 解压赋值 请求给了method 处理参数给了action
for method, action in actions.items():
# self是自定义的那个路由函数的对象
# 通过反射去对象中找action
# handler就相当于 那个执行方法的内存地址
handler = getattr(self, action)
# 反射设置值 把执行方法的内存地址覆盖了请求,每次来请求执行的就是对于的执行函数
setattr(self, method, handler)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# And continue as usual
return self.dispatch(request, *args, **kwargs)
自定义ViewSetMixin类
- 相当于映射 指定请求来了执行指定方法
from rest_framework.viewsets import ViewSetMixin
from rest_framework.views import APIView
# 要注意继承的顺序如果APIView继承在前按照mro列表先执行它里面的as_views,所以要放在前面
class Test(ViewSetMixin, APIView):
def test(self, request, pk):
print('自定义请求收到参数:', pk)
return Response()
url
url(r'^test/(?P<pk>\d+)/$', views.Test.as_view({'get': 'test'})),
drf 视图源码详解的更多相关文章
- [转]【视觉 SLAM-2】 视觉SLAM- ORB 源码详解 2
转载地址:https://blog.csdn.net/kyjl888/article/details/72942209 1 ORB-SLAM2源码详解 by 吴博 2 https://github.c ...
- Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解
Spark Streaming揭秘 Day25 StreamingContext和JobScheduler启动源码详解 今天主要理一下StreamingContext的启动过程,其中最为重要的就是Jo ...
- spring事务详解(三)源码详解
系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...
- 条件随机场之CRF++源码详解-预测
这篇文章主要讲解CRF++实现预测的过程,预测的算法以及代码实现相对来说比较简单,所以这篇文章理解起来也会比上一篇条件随机场训练的内容要容易. 预测 上一篇条件随机场训练的源码详解中,有一个地方并没有 ...
- [转]Linux内核源码详解--iostat
Linux内核源码详解——命令篇之iostat 转自:http://www.cnblogs.com/york-hust/p/4846497.html 本文主要分析了Linux的iostat命令的源码, ...
- saltstack源码详解一
目录 初识源码流程 入口 1.grains.items 2.pillar.items 2/3: 是否可以用python脚本实现 总结pillar源码分析: @(python之路)[saltstack源 ...
- Shiro 登录认证源码详解
Shiro 登录认证源码详解 Apache Shiro 是一个强大且灵活的 Java 开源安全框架,拥有登录认证.授权管理.企业级会话管理和加密等功能,相比 Spring Security 来说要更加 ...
- udhcp源码详解(五) 之DHCP包--options字段
中间有很长一段时间没有更新udhcp源码详解的博客,主要是源码里的函数太多,不知道要不要一个一个讲下去,要知道讲DHCP的实现理论的话一篇博文也就可以大致的讲完,但实现的源码却要关心很多的问题,比如说 ...
- Activiti架构分析及源码详解
目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...
随机推荐
- 搜索专题:HDU1241 Oil Deposits
Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tot ...
- 2019牛客暑期多校训练营(第八场) - B - Beauty Values - 水题
https://ac.nowcoder.com/acm/contest/888/B 实际上的确是个水题,写个小数据找个规律看看,所谓不同度,其实就是依次插入每个元素后,各种元素出现的最后位置的坐标求和 ...
- 虚拟机的linux(CentOS)系统安装
一.安装虚拟机:VirtualBox 1.软件下载:https://www.virtualbox.org/ 2.一路点击下一步完成安装 二.安装linux:CentOS6.8 1.官方网站:ht ...
- 简单的物流项目实战,WPF的MVVM设计模式(四)
接下来写ViewModels 创建运单的ViewModel类 public class CreateExpressWindowViewModel: NotificationObject { priva ...
- JS中For循环中嵌套setTimeout()方法的执行顺序
在For循环中执行setTimeOut()方法的代码,执行顺序是怎样的呢? 代码如下 function time() { for(var i= 0;i<5;i++){ setTimeout(fu ...
- python基础知识之数据类型
一.与用户的交互 古时候,我们去银行取钱,需要有一个银行业务员等着我们把自己的账号密码输入给他, 然后他去进行验证,成功后,我们再将取款金额输入/告诉他 骄傲的现代人,会为客户提供一台ATM机(就是一 ...
- SQL查询优化的步骤
一.定位慢查询 SQL优化的一般步骤:先查询mysql数据库运行状况,然后定位慢查询,再分析sql的执行过程,然后进行优化 1.使用show status查询数据库的运行状况 //显示数据库运行状态 ...
- python如何导入自定义文件和模块$PYTHONHOME$\Lib\site-packages 方法
python 中如何引用自己创建的源文件(*.py)呢? 也就是所谓的模块. 假如,你有一个自定义的源文件,文件名:saySomething.py .里面有个函数,函数名:sayHello.如下图: ...
- python装饰器的简单理解
如果你接触 Python 有一段时间了的话,想必你对 @ 符号一定不陌生了,没错 @ 符号就是装饰器的语法糖. 装饰器的使用方法很固定: 先定义一个装饰函数(帽子)(也可以用类.偏函数实现) 再定义你 ...
- 【NOIP2013模拟】DY引擎
题目 BOSS送给小唐一辆车.小唐开着这辆车从PKU出发去ZJU上课了. 众所周知,天朝公路的收费站超多的.经过观察地图,小唐发现从PKU出发到ZJU的所有路径只会有N(2<=N<=300 ...