RESTful源码笔记之RESTful Framework的APIview, Viewset总结分析
0x00 引言
官方文档:http://www.django-rest-framework.org/
drf为我们提供强大的通用view的功能,本博客对这些view进行简要的总结分析。
首先,我们看一下主要的几种view以及他们之间的关系。
这其中,还涉及了mixins,主要也分为5类:
0x01 django View
首先,我们使用django自带的view,获取一个课程的列表:
# drf是通过json的格式进行数据交互的,所以这里也返回json数据
import json
from django.views.generic.base import View
from django.core import serializers
from django.http import HttpResponse,JsonResponse
from .models import Course class CourseListView(View):
def get(self, request):
"""
通过django的view实现课程列表页
"""
courses = Course.objects.all()[:10]
json_data = serializers.serialize('json', Courses)
json_data = json.loads(json_data)
return JsonResponse(json_data, safe=False)
0x02 APIView
接下来,我们用APIView来实现
from rest_framework.views import APIView
from rest_framework.response import Response
# 这个serializers是在其他文件自定义的,这里对这个不进行过多介绍
from .serializers import CourseSerializer class CourseListView(APIView):
def get(self, request, format=None):
"""
通过APIView实现课程列表页
"""
courses = Course.objects.all()
serializer = CourseSerializer(courses, many=True)
return Response(serializer.data)
APIView对django本身的View进行封装,从上述的代码,这样分析,两者的差别看起来不是很大,但实际中APIView做了很多东西,它定义了很多属性与方法,举几个例子
# 这三个是常用的属性
authentication_classes : 用户登录认证方式,session或者token等等
permission_classes : 权限设置,是否需要登录等
throttle_classes : 限速设置,对用户进行一定的访问次数限制等等。
到这里,可能还不能体现drf通过view的强大之处,那么接下来的GenericAPIView就展示了它强大的功能。
0x03 GenericAPIView
from rest_framework import mixins
from rest_framework import generics
class CourseListView(mixins.ListModelMixin, generics.GenericAPIView):
"""
课程列表页
"""
queryset = Course.objects.all()
serialize_class = CourseSerializer
def get(self, request, *args, **kwargs):
# list方法是存在于mixins中的,同理,create等等也是
# GenericAPIView没有这些方法!
return self.list(request, *args, **kwargs)
在这个例子中,继承了mixins中的ListModelMixin,在get( )方法中,调用了它的list()方法,list方法会返回queryset的json数据。这里对mixins不进行过多的介绍。 GenericAPIView对APIView再次封装,实现了强大功能:
- 加入queryset属性,可以直接设置这个属性,不必再将实例化的courses,再次传给seriliazer,系统会自动检测到。除此之外,可以重载get_queryset(),这样就不必设置'queryset=*',这样就变得更加灵活,可以进行完全的自定义。
- 加入serializer_class属性与实现get_serializer_class()方法。两者的存在一个即可,通过这个,在返回时,不必去指定某个serilizer
- 设置过滤器模板:filter_backends
- 设置分页模板:pagination_class
- 加入 lookup_field="pk",以及实现了get_object方法:这个用得场景不多,但十分重要。它们两者的关系同1,要么设置属性,要么重载方法。它们的功能在于获取某一个实例时,指定传进来的后缀是什么。
举个例子,获取具体的某个课程,假设传进来的ulr为:http://127.0.0.1:8000/course/1/,系统会默认这个1指的是course的id。那么,现在面临一个问题,假设我定义了一个用户收藏的model,我想要知道我id为1的课程是否收藏了,我传进来的url为:http://127.0.0.1:8000/userfav/1/,系统会默认获取userfav的id=1的实例,这个逻辑明显是错的,我们需要获取course的id=1的收藏记录,所以我们就需要用到这个属性或者重载这个方法 lookup_field="course_id"。
在generics除了GenericAPIView还包括了其他几个View: CreateAPIView、ListAPIView、RetrieveAPIView、ListCreateAPIView···等等,其实他们都只是继承了相应一个或多个mixins和GenericAPIView,这样,有什么好处?我们看一下同样一个例子的代码:
class CourseListView(ListAPIView):
"""
课程列表页
"""
queryset = Course.objects.all()
serialize_class = CourseSerializer
这样,就完成了和刚刚一模一样的功能!
0x04 GenericViewSet
- GenericAPIView的不足之处
首先,我们思考一个问题,同样上面的例子,我们在功能上,要获取课程的列表,也要获取某个课程的具体信息。那么怎么实现,按照GenericAPIView,我们可以这样实现:
class CourseView(ListAPIView,RetrieveAPIView):
# 只需要在上面的基础上,再继承RetrieveAPIView就ok了。
queryset = Course.objects.all()
serialize_class = CourseSerializer
但这样实现有一个问题,关于serialize_class,显然,当获取课程列表时,只需要传回去所有课程的简要信息,如课程名字,老师,封面等等,但当获取课程的具体信息,我们还要将他们的章节以及相关下载资料(很明显,章节是另外一个model,有一个外键指向course),这些信息会很多,在获取课程列表,将这些传回去显然是不理智的。那么,还需要再定义一个CourseDetailSerializer,在get /courses/的时候,使用CourseSerializer,在get /courses/id/的时候,使用CourseDetailSerializer。
那么,问题来了,我们怎么获取到是哪个action方法?这个时候,viewset就出场了!
- viewset的功能
GenericViewSet继承了GenericAPIView,依然有get_queryset,get_serialize_class相关属性与方法,GenericViewSet重写了as_view方法,可以获取到HTTP的请求方法。
解决刚刚的问题:
from rest_framework import viewsets
import...
class CourseViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = Course.objects.all() def get_serializer_class(self):
# 重写get_serializer_class方法
if self.action == 'list':
return CourseSerializer
return CourseDetailSerializer
- http请求方法与mixins的方法进行绑定
但GenericViewSet本身依然不存在list, create方法,需要我们与mixins一起混合使用,那么新问题来了?我们依然需要自己写get、post方法,然后再return list或者create等方法吗?当然不!重写as_view的方法为我们提供了绑定的功能,我们在设置url的时候:
# 进行绑定
courses = CourseViewSet.as_view({
'get': 'list',
'post': 'create'
})
urlpatterns = [
...
# 常规加入url匹配项
url(r'courses/', CourseViewSet.as_view(), name='courses'),]
这样,我们就将http请求方法与mixins方法进行了关联。那么还有更简洁的方法吗?很明显,当然有,这个时候,route就登场了!
- viewset的功能
GenericViewSet继承了GenericAPIView,依然有get_queryset,get_serialize_class相关属性与方法,GenericViewSet重写了as_view方法,可以获取到HTTP的请求方法。 解决刚刚的问题:
from rest_framework import viewsets
import...
class CourseViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = Course.objects.all() def get_serializer_class(self):
# 重写get_serializer_class方法
if self.action == 'list':
return CourseSerializer
return CourseDetailSerializer
- http请求方法与mixins的方法进行绑定
但GenericViewSet本身依然不存在list, create方法,需要我们与mixins一起混合使用,那么新问题来了?我们依然需要自己写get、post方法,然后再return list或者create等方法吗?当然不!重写as_view的方法为我们提供了绑定的功能,我们在设置url的时候
# 进行绑定
courses = CourseViewSet.as_view({
'get': 'list',
'post': 'create'
})
urlpatterns = [
...
# 常规加入url匹配项
url(r'courses/', CourseViewSet.as_view(), name='courses'),]
这样,我们就将http请求方法与mixins方法进行了关联。那么还有更简洁的方法吗?很明显,当然有,这个时候,route就登场了!
- route方法注册与绑定
from rest_framework.routers import DefaultRouter
router = DefaultRouter() # 只需要实现一次
router.register(r'courses', CourseViewSet, base_name='courses')
urlpatterns = [
...
# 只需要加入一次
url(r'^', include(router.urls)),]
在viewset中,还提供了两个以及与mixins绑定好的ViewSet,当然,这两个ViewSet完全可以自己实现:
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# 满足只有GET方法请求的情景
pass class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# 满足所有请求都有的情景
pass
到这里,ViewSet的强大功能就介绍完了,强烈建议在做drf的时候,使用ViewSet与mixins方法结合进行开发,为我这种小白开发者提供了很强大完整的功能!
参考
RESTful源码笔记之RESTful Framework的APIview, Viewset总结分析的更多相关文章
- RESTful源码笔记之RESTful Framework的Mixins小结
0x00 引言 本篇对drf中的mixins进行简要的分析总结.Mixins在drf中主要配合viewset共同使用,实现http方法与mixins的相关类与方法进行关联. from rest_fra ...
- RESTful源码笔记之RESTful Framework的基本组件
快速实例 Quickstart 序列化 创建一个序列化类 简单使用 开发我们的Web API的第一件事是为我们的Web API提供一种将代码片段实例序列化和反序列化为诸如json之类的表示形式的方式. ...
- Zepto源码笔记(一)
最近在研究Zepto的源码,这是第一篇分析,欢迎大家继续关注,第一次写源码笔记,希望大家多指点指点,第一篇文章由于首次分析原因不会有太多干货,希望后面的文章能成为各位大大心目中的干货. Zepto是一 ...
- redis源码笔记(一) —— 从redis的启动到command的分发
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载联系作者并保留声明头部与原文链接https://luzeshu.com/blog/redis1 本博客同步在http://www.cnblog ...
- AsyncTask源码笔记
AsyncTask源码笔记 AsyncTask在注释中建议只用来做短时间的异步操作,也就是只有几秒的操作:如果是长时间的操作,建议还是使用java.util.concurrent包中的工具类,例如Ex ...
- Java Arrays 源码 笔记
Arrays.java是Java中用来操作数组的类.使用这个工具类可以减少平常很多的工作量.了解其实现,可以避免一些错误的用法. 它提供的操作包括: 排序 sort 查找 binarySearch() ...
- Tomcat8源码笔记(八)明白Tomcat怎么部署webapps下项目
以前没想过这么个问题:Tomcat怎么处理webapps下项目,并且我访问浏览器ip: port/项目名/请求路径,以SSM为例,Tomcat怎么就能将请求找到项目呢,项目还是个文件夹类型的? Tom ...
- Tomcat8源码笔记(七)组件启动Server Service Engine Host启动
一.Tomcat启动的入口 Tomcat初始化简单流程前面博客介绍了一遍,组件除了StandardHost都有博客,欢迎大家指文中错误.Tomcat启动类是Bootstrap,而启动容器启动入口位于 ...
- Tomcat8源码笔记(六)连接器Connector分析
根据 Tomcat8源码笔记(五)组件Container分析 前文分析,StandardService的初始化重心由 StandardEngine转移到了Connector的初始化,本篇记录下Conn ...
随机推荐
- Effective C++ —— 定制new和delete(八)
STL容器所使用的heap内存是由容器所拥有的分配器对象管理,不是被new和delete直接管理.本章并不讨论STL分配器. 条款49 : 了解new-handler的行为 当operator new ...
- c语言基础知识要点
C语言程序的构成 与C++.Java相比,C语言其实很简单,但却非常重要.因为它是C++.Java的基础.不把C语言基础打扎实,很难成为程序员高手. 一.C语言的结构 先通过一个简单的例子,把C语言的 ...
- 微信accesstoken回调
errcode=-1的时候,开发文档中说明是系统异常,至于具体原因不明 不过有一种原因是AppID以及AppSecret错误 其它可能原因还待发现
- PHP面向对象 实例化 构造函数 封装 继承 静态
PHP面向对象 实例化 构造函数 封装 继承 静态 面向对象: 一:定义类 class Dog { var $name; var $age; var $pinzhong; function Jiao( ...
- <转>与EM相关的两个算法-K-mean算法以及混合高斯模型
转自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006924.html http://www.cnblogs.com/jerrylead/ ...
- (转)关于android设备管理器的一些分析
转自http://bbs.pediy.com/showthread.php?t=183692 想必很多人都知道轰动一时android木马OBAD,该木马利用android设备管理器的漏洞,当用户激活设 ...
- 让ASP.NET OutputCache使用http.sys kernel-mode cache
在默认情况下,http.sys kerne mode cache只缓存静态文件. 那我们如何让ASP.NET OutputCache直接使用http.sys kerne mode cache?这样缓存 ...
- 使用C#和HtmlAgilityPack解析HTML
近期,有一个需求,需要解析HTML页面,读取一些需要的数据后,插入本地数据库.我知道可以通过正则表达式实现,然而正则表达式之于我,就像汇编语言之于我,一样.我知道它是干什么的,我也知道它能干什么,但是 ...
- HDU_5521_Meeting
Meeting Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total ...
- Eclipse For Android 代码自动提示功能
Eclipse for android 实现代码自动提示智能提示功能,介绍 Eclipse for android 编辑器中实现两种主要文件 java 与 xml 代码自动提示功能,解决 eclips ...