DRF 通用视图-视图工具类-视图集以及路由
:::tip Django REST Framework. Generic Views, MixIns, ViewSets and Routers :::
基本信息
源码仓库
官方文档
关系图
::: details View继承图与View图谱 :::
AIPView-API视图类
APIView 是 Django REST Framework 提供的所有视图的基类,继承自 Django 的 View 父类
AIPView 对比 Django View
- 传入到视图方法中的是 REST framework 的 Request 对象,而不是 Django 的 HttpRequeset 对象
- 视图方法可以返回 REST framework 的 Response 对象,视图会为响应数据设置(render)符合前端要求的格式
- 任何 APIException 异常都会被捕获到,并且处理成合适的响应信息
- 在进行 dispatch() 分发前,会对请求进行身份认证、权限检查、流量控制
重要类属性
AIPView 有如下可设置的重要类属性:
- authentication_classes:列表或元祖,身份认证类
- permissoin_classes: 列表或元祖,权限检查类
- throttle_classes: 列表或元祖,流量控制类
示例
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from models import Goods
from serializers import GoodsSerializer
class GoodListView(APIView):
def get(self, request):
goods = Goods.objects.all()
serializer = GoodsSerializer(goods, many=True)
return Response(serializer.data)
serializers.py
class GoodsSerializer(serializers.ModelSerializer):
# category = CategorySerializer()
# images = GoodsImageSerializer(many=True)
class Meta:
model = Goods
fields = "__all__"
GenericAPIView-通用API视图类
通用 API 视图类 GenericAPIView 继承自 APIView,完全兼容 APIView,主要增加了操作序列化器和数据库查询的方法,作用是为下面 Mixin 扩展类的执行提供基础类支持。通常在使用时,可以配合一个或多个 Mixin 扩展类。
GenericAPIView 对比 APIView
- get_queryset(): 从类属性 queryset中获得 model 的 queryset 数据。群操作就走 get_queryset() 方法 (包括群查,群增等)。
- get_object(): 从类属性 queryset 中获得 model 的 queryset 数据,再通过有名分组 pk 确定唯一操作对象。单操作就走 get_object() 方法(包括单查,单增等)。
- get_serializer():从类属性 serializer_class 中获得 serializer 的序列化类。
重要类属性
- 列表视图与详情视图共用
- queryset: 指明视图需要的数据(model 查询数据)
- permissoin_classes:指明视图使用的序列化器
- 列表视图使用
- pagination_class:指定分页控制类
- filter_backends: 指定过滤控制后端
- 详情页视图使用
- lookup_field: 自定义主键,有名分组的查询,默认是 pk
- lookup_url_kwarg:查询单一数据时 url 中的参数关键字名称,默认与 look_field 相同
重要类方法
- get_queryset(): 从类属性 queryset 中获得 model 的 queryset 数据
- get_object(): 从类属性 queryset 中获得 model 的 queryset 数据,再通过有名分组 pk 来确定唯一操作对象
- get_serializer():从类属性 serializer_class 中获得 serializer 的序列化类,主要用来提供给 Mixin 扩展类使用
get_serializer 源码
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
返回应该用于验证和反序列化输入以及序列化输出的序列化器实例。
"""
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
示例
views.py
class GoodGenericAPIView(GenericAPIView):
queryset = models.Good.objects.filter(is_delete=False)
serializer_class = serializers.GoodModelSerializer
lookup_field = 'pk' # 先定义好,单查可以使用,默认是pk 自定义主键的有名分组,如果路由有名分组不是pk,这个属性就要自己设置了
# 群取
def get(self, request, *args, **kwargs):
good_query = self.get_queryset() # 获取queryset数据(model查询数据)
good_ser = self.get_serializer(good_query, many=True)
good_data = good_ser.data
return APIResponse(results=good_data)
# # 单取
# def get(self, request, *args, **kwargs):
# good_query = self.get_object()
# good_ser = self.get_serializer(good_query)
# good_data = good_ser.data
# return APIResponse(results=good_data)
urls.py
urlpatterns = [
path('v2/goods/', views.GoodGenericAPIView.as_view()),
path('v2/goods/<pk>/', views.GoodGenericAPIView.as_view()),
]
xxxModelMixin-视图类的模型工具集
作用
- 提供了几种后端视图(对数据资源的增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
- mixins 有五个工具类文件,一共提供了五个工具类,六个工具方法:单查、群查、单增、单删、单整体改、单局部改
使用
- 继承工具类可以简化请求函数的实现体,但是必须继承 GenericAPIView,需要 GenericAPIView 类提供序列化器与数据库查询的方法 (见上方 GenericAPIView 基类知识点)
- 工具类的工具方法返回值都是 Response 类型对象,如果要格式化数据格式再返回给前台,可以通过 response.data 拿到工具方法返回的 Response 类型对象的响应数据
五大模型工具类
- ListModelMixin 群查
- 列表视图扩展类,提供 list 方法快速实现查询视图
- 返回 200 状态码
- 除了查询,该 list 方法会对数据进行过滤和分页
- CreateModelMixin 单增
- 创建视图扩展类,提供 create 方法快速创建资源的视图,成功返回 201 的状态码
- 没有群增的方法,需要自己手动写
- RetrieveModelMixin 单查
- 详情视图扩展类,提供 retrieve 方法,可以快速实现返回一个存在的数据对象
- UpdateModelMixin 更新 / 修改
- 更新视图扩展类,提供 update 方法,可以快速实现更新一个存在的数据对象,同时也提供 partial_update 方法,可以实现局部更新
- 只有单整体改和单局部改,没有群整体改和群局部改
- DestoryModelMixin 删除
- 删除视图扩展类,提供 destory 方法,可以快速实现删除一个存在数据对象
- 一般不怎么用到,因为实际开发中并不会真的删除数据,而是修改是否可用的标记
示例
views.py
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin
class GoodMixinGenericAPIView(ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericAPIView):
# GenericAPIView提供的序列化器和查询的数据
queryset = models.Good.objects.filter(is_delete=False)
serializer_class = serializers.GoodModelSerializer
# 单查和群查
def get(self, request, *args, **kwargs):
if 'pk' in kwargs:
# 单查 RetrieveModelMixin方法
response = self.retrieve(request, *args, **kwargs)
else:
# mixins提供的list方法的响应对象是Response,将该对象格式化为自定义的APIResponse
response = self.list(request, *args, **kwargs) # 群查 ListModelMixin
# response的数据都存放在response.data中
return APIResponse(results=response.data)
# 单增
def post(self, request, *args, **kwargs):
response = self.create(request, *args, **kwargs) # CreateModelMixin方法
return APIResponse(results=response.data)
# 单整体修改
def put(self, request, *args, **kwargs):
response = self.update(request, *args, **kwargs) # UpdateModelMixin
return APIResponse(results=response.data)
# 单局部修改
def patch(self, request, *args, **kwargs):
response = self.partial_update(request, *args, **kwargs)
return APIResponse(results=response.data)
urls.py
urlpatterns = [
path('v3/goods/', views.GoodMixinGenericAPIView.as_view()),
path('v3/goods/<pk>/', views.GoodMixinGenericAPIView.as_view()),
]
xxxAPIView-功能性子视图类
功能性子视图类继承了 GenericAPIView 和各种 Mixins 工具类
- 功能性视图类都是 GenericAPIView 的子类,且不同的子类继承了不同的工具类
- 功能性视图类的功能可以满足需求,只需要继承工具视图,并且提供 queryset 与 serializer_class 即可
各大功能子视图类
视图 | 作用 | 请求类型 | 父类 |
---|---|---|---|
ListAPIView | 查询多条数据 | get | GenericAPIView ListModelMixin |
CreateAPIView | 新增一条数据 | post | GenericAPIView CreateModelMixin |
RetrieveAPIView | 查询一条数据 | get | GenericAPIView RetrieveModelMixin |
UpdateAPIView | 修改一条数据 | put patch | GenericAPIView UpdateModelMixin |
DestroyAPIView | 删除一条数据 | delete | GenericAPIView DestroyModelMixin |
RetrieveUpdateAPIView | 单查 更新一条 | get put patch | GenericAPIView RetrieveModelMixin UpdateModelMixin |
RetrieveUpdateDestroyAPIView | 单查 更新删除一条 | get put patch delete | GenericAPIView RetrieveModelMixin UpdateModelMixin DestroyModelMixin |
ListCreateAPIView | 群查 更新一条 | get post | GenericAPIView ListModelMixin mixins.CreateModelMixin |
xxxViewset-视图集
常用视图集父类
ViewSetMixin
ViewSetMixin 主要是自定义了 as_view 方法,使可以通过其参数指定 HTTP_METHOD 与函数的映射关系,如 view = MyViewSet.as_view({‘get’: ’list’, ‘post’: ‘create’})
ViewSet
继承自 APIView 和 ViewSetMixin,没有提供任何方法,需要自己写
GenericViewSet
继承 GenericAPIView 和 ViewSetMixin,其中 GenericAPIView 提供了基础方法,可以直接搭配 Mixin 扩展类使用,因此比较常用
ModelViewSet
继承 GenericViewset,但同时也包括 ListModelMixin、CreateModelMixin 等 mixin 扩展类
源码分析
- 视图集都是默认优先继承 ViewSetMixin 类,再继承一个视图类(GenericAPIView 或 APIView)
- ViewSetMixin 提供了重写的 as_view() 方法,继承视图集的视图类,配置路由时调用 as_view() 必须传入 请求名 - 函数名 映射关系字典
例如:
# 表示 get 请求会交给 my_get_list 视图函数处理
path('v5/books/', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
GenericViewSet 示例代码
urls.py
urlpatterns = [
# View的as_view():将get请求映射到视图类的get方法
# ViewSet的as_view({'get': 'my_get_list'}):将get请求映射到视图类的my_get_list方法
path('v5/books/', views.BookGenericViewSet.as_view({'get': 'my_get_list'})),
path('v5/books/<pk>/', views.BookGenericViewSet.as_view({'get': 'my_get_obj'})),
]
views.py
from rest_framework.viewsets import GenericViewSet
from rest_framework import mixins #工具集 可以使用list, retrieve等方法
class BookGenericViewSet(RetrieveModelMixin, ListModelMixin, GenericViewSet):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BookModelSerializer
def my_get_list(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def my_get_obj(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
GenericViewSet 与 ViewSet
异同
- GenericViewSet 和 ViewSet 都继承了 ViewSetMixin,as_view 都可以配置 请求 - 函数 映射
- GenericViewSet 继承的是 GenericAPIView 视图类,用来完成标准的 model 类操作接口
- ViewSet 继承的是 APIView 视图类,用来完成不需要 model 类参与,或是非标准的 model 类操作接口,如
- post 请求在标准的 model 类操作下就是新增接口,登陆的 post 不满足。登陆的 post 请求,并不是完成数据的新增,只是用 post 提交数据,得到的结果也不是登陆的用户信息,而是登陆的认证信息
- post 请求验证码的接口,不需要 model 类的参与
源码
GenericViewSet
# viewsets.py
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
"""
The GenericViewSet class does not provide any actions by default,
but does include the base set of generic view behavior, such as
the `get_object` and `get_queryset` methods.
默认情况下,GenericViewSet类不提供任何操作,但是包含通用视图行为的基本集,比如get ohiect和get queryset方法
"""
pass
# generics.py
class GenericAPIView(views.APIView):
# ...
# vies.py
class APIView(View):
# ...
ViewSet
class ViewSet(ViewSetMixin, views.APIView):
"""
The base ViewSet class does not provide any actions by default.
默认情况下,基本ViewSet类不提供任何操作。
"""
pass
# vies.py
class APIView(View):
# ...
ModelViewSet 示例代码
urls.py
urlpatterns = [
path('v6/books/', views.BookModelViewSet.as_view({'get': 'list', 'post': 'create'})),
path('v6/books/<pk>/', views.BookModelViewSet.as_view({'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]
views.py
class BookModelViewSet(ModelViewSet):
queryset = models.Book.objects.filter(is_delete=False)
serializer_class = serializers.BookModelSerializer
# 删不是数据库,而是该记录中的修改is_delete的值,因此重写默认的destroy函数
def destroy(self, request, *args, **kwargs):
instance = self.get_object() # type: models.Book
if not instance:
return APIResponse(1, '删除失败') # 实际操作,在此之前就做了判断
instance.is_delete = True
instance.save()
return APIResponse(0, '删除成功')
路由组件
因为具有局限性,所以在开发复杂接口时并不是首选。
示例代码如下:
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from . import views
router = SimpleRouter()
# 所有路由与ViewSet视图类的都可以注册,会产生 'v7/books/' 和 'v7/books/<pk>/'
router.register('v7/books', views.BookModelViewSet)
urlpatterns = [
# router.urls 添加方法一
# path('', include(router.urls)),
]
# router.urls 添加方法二
# urlpatterns += router.urls