Django Rest Framework(3)-----APIView与Viewsets
REST framework提供了一个APIView
类,它是Django的View
类的子类。
REST framework主要的几种view以及他们之间的关系:
mixins
到目前为止,我们使用的创建/获取/更新/删除操作和我们创建的任何基于模型的API视图非常相似。这些常见的行为是在REST框架的mixin类中实现的
Mixin 类提供用于提供基本视图行为的操作。注意mixin类提供动作方法,而不是直接定义处理程序方法,例如 .get()
和 .post()
, 这允许更灵活的行为组成。
Mixin 类可以从 rest_framework.mixins
导入。
mixins | 作用 | 对应HTTP的请求方法 |
mixins.ListModelMixin |
定义list方法,返回一个queryset的列表 |
GET |
mixins.CreateModelMixin | 定义create方法,创建一个实例 | POST |
mixins.RetrieveModelMixin | 定义retrieve方法,返回一个具体的实例 | GET |
mixins.UpdateModelMixin | 定义update方法,对某个实例进行更新 | PUT/PATCH |
mixins.DestroyModelMixin | 定义delete方法,删除某个实例 | DELETE |
使用详解
1.APIView
APIView对django本身的View进行封装
APIView
类和一般的View
类有以下不同:
被传入到处理方法的请求不会是Django的
HttpRequest
类的实例,而是REST framework的Request
类的实例。处理方法可以返回REST framework的
Response
,而不是Django的HttpRequest
。视图会管理内容协议,给响应设置正确的渲染器。任何
APIException
异常都会被捕获,并且传递给合适的响应。进入的请求将会经过认证,合适的权限和(或)节流检查会在请求被派发到处理方法之前
authentication_classes:用户登录认证方式,session或者token等等。
permission_classes:权限设置,是否需要登录等。
throttle_classes:限速设置,对用户进行一定的访问次数限制等等
使用APIView
类和使用一般的View
类非常相似,通常,进入的请求会被分发到合适处理方法比如.get()
,或者.post
。另外,很多属性会被设定在控制API策略的各种切面的类上。
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions class ListUsers(APIView):
"""
列出系统中的所有用户的视图。 * 需要token认证
* 只有管理员用户可以访问这个视图。
"""
authentication_classes = (authentication.TokenAuthentication,)
permission_classes = (permissions.IsAdminUser,) def get(self, request, format=None):
"""
Return a list of all users.
"""
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
2.GenericAPIView
该类对APIView进行更高层次的封装,扩展了REST框架的 APIView
类,为标准list和detail view 添加了通常需要的行为。
提供的每个具体通用视图是通过将 GenericAPIView
与一个或多个mixin类组合来构建的。
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,就是对应把HTTP的get方法转换调用list方法,list方法会返回queryset的json数据
GenericAPIView对APIView再次封装,实现了强大功能:
- 加入queryset属性,可以直接设置这个属性,不必再将实例化的data,再次传给seriliazer,系统会自动检测到。除此之外,可以重载get_queryset(),这样就不必设置’queryset=*’,这样就变得更加灵活,可以进行完全的自定义。
- 加入serializer_class属性与实现get_serializer_class()方法。两者的存在一个即可,通过这个,在返回时,不必去指定某个serializer。
- 设置过滤器模板:filter_backends。
- 设置分页模板:pagination_class。
- 加入 lookup_field=”pk”,以及实现了get_object方法,这个用得场景不多,但十分重要。它们两者的关系同1,要么设置属性,要么重载方法。它们的功能在于获取某一个实例时,指定传进来的后缀是什么。
例如·,获取具体的某个课程,假设传进来的URL为: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”这个方法。
GenericAPIView的不足之处:
既然GenericAPIView以及它相关的View已经完成了许许多多的功能,那么还要ViewSet干嘛!
首先,我们思考一个问题,同样上面的例子,我们在功能上,要获取课程的列表,也要获取某个课程的具体信息。那么怎么实现,按照GenericAPIView,我们可以这样实现:
class CourseView(ListAPIView,RetrieveAPIView):
# 只需要在上面的基础上,再继承RetrieveAPIView就ok了。
queryset = Course.objects.all()
serialize_class = CourseSerializer
那么,问题来了,我们怎么获取到是哪个action方法?这个时候,viewset就出场了!
3.Viewset
GenericViewSet继承了GenericAPIView,依然有get_queryset,get_serialize_class相关属性与方法,GenericViewSet重写了as_view方法,可以获取到HTTP的请求方法。
使用ViewSet
类比使用View
类有两个主要优点。
- 重复逻辑可以组合成一个类。在上面的示例中,我们只需要指定
queryset
一次,它将在多个视图中使用。 - 通过使用路由器,我们不再需要处理自己的URL连接。
如:上述问题中我们可以这样解决
法一:
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方法注册与绑定
因为我们使用ViewSet类而不是View类,实际上不用自己设计URL conf及绑定HTTP方法。连接resources到views和urls的约定可以使用Router类自动处理。我们需要做的仅仅是正确的注册View到Router中,然后让它执行其余操作。新的urls.py代码如下:
from rest_framework.routers import DefaultRouter
router = DefaultRouter() # 只需要实现一次
router.register(r'courses', CourseViewSet, base_name='courses')
urlpatterns = [
...
# 只需要加入一次
url(r'^', include(router.urls)),]
route中使用的一定要是ViewSet,用router.register的方法注册url不仅可以很好的管理url,不会导致url过多而混乱,而且还能实现http方法与mixins中的相关方法进行连接。
ModelViewSet:
在viewset中,还提供了两个以及与mixins绑定好的ViewSet。当然,这两个ViewSet完全可以自己实现,它只是把各类mixins与GenericViewSet继承在一起了:
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# 满足只有GET方法请求的情景
pass class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
# 满足所有请求都有的情景
pass
在开发的时候,直接继承 viewsets.ModelViewSet 就可以了,这样就不用写list、create、update等方法了,当然具体问题具体分析,如果你的需求与DRF提供的不一致,那么你就可以重写相应的方法即可
假如有这样一个需求,你可能需要过滤查询集,以确保只返回与当前通过身份验证的用户发出的请求相关的结果。
class CourserViewSet(ModelViewSet):
"""
每个用户只可以查看owner属于自己的条目,可以创建条目
""" def list(self, request, *args, **kwargs):
self.queryset = Course.objects.filter(owner=request.user.id)
self.serializer_class = CourseSerializer
return super(CourserViewSet, self).list(request, *args, **kwargs) def create(self, request, format=None):
serializer = CourseSerializer(data=request.data)
if serializer.is_valid():
# .save()是调用CourseSerializer中的create()方法
serializer.save(owner=self.request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
这里定义了两个方法,list方式中我们我们重写了queryset(就是对返回结果做了一次过滤),然后对于serializer_class指定了一个序列化类。并且我们使用super方法,继续载入viewset中的list方法,这里只会覆盖原有list的queryset和serializer_class。而对于create方法,我们则是完全重写了原viewset中的create方法。这里只是演示一下再ViewSet模式下如何来做工作。原则就是能用ViewSet内置的就是用内置的,内置的不满足需求就可以重写部分或全部重写。
另外,如果只是过滤查询集,最简单方法是重写.get_queryset()
方法即可。重写此方法允许你以多种不同方式自定义视图返回的查询集。
class CourseViewSet(ModelViewSet):
"""
每个用户只可以查看owner属于自己的条目,可以创建条目
""" serializer_class = CourseSerializer def list(self, request, *args, **kwargs):
return Course.objects.filter(owner=request.user.id)
自定义ViewSet基类
要创建基础视图集类,提供create
,list
和retrieve
操作,继承GenericViewSet
和混入所需的操作:
class CreateListRetrieveViewSet(mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
"""
A viewset that provides `retrieve`, `create`, and `list` actions. To use it, override the class and set the `.queryset` and
`.serializer_class` attributes.
"""
pass
ps:在开发时是使用ViewSet与mixins方法结合进行可以为我们节省很多功夫
参考:
https://q1mi.github.io/Django-REST-framework-documentation/api-guide/generic-views_zh/
https://www.django-rest-framework.org/api-guide/viewsets/
http://www.ywnds.com/?p=14104
Django Rest Framework(3)-----APIView与Viewsets的更多相关文章
- Django REST framework 第六章 ViewSets & Routers
REST framework包含了一个可以处理ViewSets的抽象, 它允许开发人员专注于API的状态跟交互进行建模,并使得URL构建结构基于通用的约定自动处理. ViewSet类跟View类几乎相 ...
- Django rest framework框架——APIview源码分析
一.什么是rest REST其实是一种组织Web服务的架构,而并不是我们想象的那样是实现Web服务的一种新的技术,更没有要求一定要使用HTTP.其目标是为了创建具有良好扩展性的分布式系统. 可用一句话 ...
- Django REST FrameWork中文教程2:请求和响应
从这一点开始,我们将真正开始覆盖REST框架的核心.我们来介绍几个基本的构建块. 请求对象REST框架引入了Request扩展常规的对象HttpRequest,并提供更灵活的请求解析.Request对 ...
- Django REST framework 中文教程1:序列化
建立环境 在我们做任何事情之前,我们将使用virtualenv创建一个新的虚拟环境.这将确保我们的包配置与我们正在开展的任何其他项目保持良好的隔离. virtualenv envsource env/ ...
- 轻轻松松学会 DRF Django REST framework
据我了解,目前的IT行业的大部分后端开发,都是需要进行前后端分离的,而前后端分类必不可少的是rest 规范,以下是django rest framework的学习路径: DRF Django REST ...
- Django REST framework使用ViewSets的自定义路由实现过程
在Django中使用基于类的视图(ClassView),类中所定义的方法名称与Http的请求方法相对应,才能基于路由将请求分发(dispatch)到ClassView中的方法进行处理,而Django ...
- DRF Django REST framework APIView(一)
什么是REST? REST是一个标准,一种规范,遵循REST风格可以使开发的接口通用,便于调用者理解接口的作用. 使url更容易理解,让增删改清晰易懂,在前后端分离开发中按照这一规范能加快开发效率,减 ...
- Django REST framework+Vue 打造生鲜超市(四)
五.商品列表页 5.1.django的view实现商品列表页 (1)goods/view_base.py 在goods文件夹下面新建view_base.py,为了区分django和django res ...
- Django REST framework+Vue 打造生鲜超市(五)
六.商品类别数据展示 6.1. 商品类别数据接口 (1)商品分类有两个接口: 一种是全部分类:一级二级三级 一种是某一类的分类以及商品详细信息: 开始写商品分类的接口 (2)序列化 给分类添加三级分类 ...
随机推荐
- android开发源代码分析--多个activity调用多个jni库的方法
android开发源代码分析--多个activity调用多个jni库的方法 有时候,我们在开发android项目时会遇到须要调用多个native c/jni库文件,下面是本人以前实现过的方法,假设有知 ...
- ios开发之--ZHPickView输出格式不出现 +0000
这样写就不会输出 +0000了 NSDate *select = [_datePicker date]; NSDateFormatter *dateFormatter = [[NSDateFormat ...
- B-J UI框架(前端异步框架)
B-JUI 客户端框架 http://xiangzhanyou.com/B-JUI
- Redis(二)-- 发布订阅、事务、安全、持久化
一.Redis发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. 打开两个窗口:session1 和 session2 在sess ...
- linux系统socket通信编程实践
简单介绍并实现了基于UDP(TCP)的windows(UNIX下流程基本一致)下的服务端和客户端的程序,本文继续探讨关于UDP编程的一些细节. 下图是一个简单的UDP客户/服务器模型: 我在这里也实现 ...
- 怎样使用es6 export,import不会报错
如果浏览器支持es6的话,需要加上type="module" <script type="module"> import Store from &q ...
- 教程Xcode 下编译发布与提交App到AppStore
The proplem of Prepare for Upload for App store upload Application App store 增加新应用的步骤. 1. 访问iTunesCo ...
- Android 实现动态匹配输入的内容 AutoCompleteTextView和MultiAutoCompleteTextView
AutoCompleteTextView1.功能:动态匹配输入的内容,如百度搜索引擎当输入文本时可以根据内容显示匹配的热门信息.2.独特属性:android:completionThreshold 设 ...
- poj_1390 动态规划
题目大意 将一些连续的序列根据颜色分为N段,每段有颜色 为 Ci, 长度为 Li.每次点击其中的一段 i ,则可以将该段i消除,该段相邻的两段自动连接到一起,如果连接到一起的两段之前的颜色相同,则更新 ...
- 【BZOJ5100】[POI2018]Plan metra 构造
[BZOJ5100][POI2018]Plan metra Description 有一棵n个点的无根树,每条边有一个正整数权值,表示长度,定义两点距离为在树上的最短路径的长度. 已知2到n-1每个点 ...