DRF之视图类

视图基类

DRF视图类中除了APIView类,还有一个GenericAPIView类。

GenericAPIView类主要给我们提供了2个属性,3个方法。

2个属性:

  • queryset:要序列化的数据
  • serializer_class:序列化类

3个方法:

  • get_queryset():获取要序列化的数据
  • get_object():根据条件获取对象
  • get_serializer():获取序列化类

CBV使用(第一层)

from rest_framework.generics import GenericAPIView

# 查询所有数据、添加数据接口
class BookView(GenericAPIView):
    """重写属性"""
    # 数据库数据
    queryset = models.Book.objects.all()
    # 序列化类
    serializer_class = serializer.BookSerializer
    def get(self, request):
        """使用父类方法获取属性"""
        book_list = self.get_queryset()
        ser = self.get_serializer(instance=book_list, many=True)
        return Response(ser.data)

    def post(self, request):
        """使用父类方法获取属性"""
        ser = self.get_serializer(data=request.data)
        if ser.is_vaild():
            ser.save()
            return Response({'code': 100, 'msg': '添加成功'})
        return Response({'code': 99, 'msg': '添加失败'})

# 查询一个数据、修改数据、删除数据接口
class BookDetailView(GenericAPIView):
    """重写属性"""
    # 数据库数据
    queryset = models.Book.objects.all()
    # 序列化类
    serializer_class = serializer.BookSerializer

    def get(self, request, *args, **kwargs):
        """使用父类方法获取属性"""
        book_obj = self.get_object()
        ser = self.get_serializer(instance=book_obj)
        return Response(ser.data)
    
    def put(self, request, *args, **kwargs):
        ...
    
    def delete(self, request, *args, **kwargs):
        ...

路由配置:转换器传的参数名一定要是'pk'。

path('books/', views.BookView.as_view()),
path('books/<int:pk>', views.BookDetailView.as_view())

GenericAPIView类是不是感觉没有比APIView类方便?别急,这只是前戏!

视图扩展类

DRF里还有5个视图拓展类,可以实现我们的五个接口。

from rest_framework.mixins import ListModelMixin
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin
from rest_framework.mixins import UpdateModelMixin
from rest_framework.mixins import DestroyModelMixin

ListModelMixin类

提供查询所有数据的方法:

image

RetrieveModelMixin类

提供查询单个数据的方法:

image

CreateModelMixin类

提供添加数据的方法:

image

UpdateModelMixin类

提供更新数据的方法:

image

DestroyModelMixin类

提供删除数据的方法:

image

CBV使用(第二层)

from rest_framework.mixins import ListModelMixin
from rest_framework.mixins import RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin
from rest_framework.mixins import UpdateModelMixin
from rest_framework.mixins import DestroyModelMixin
from rest_framework.generics import GenericAPIView

# 查询所有数据、添加数据接口
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
    """重写属性"""
    # 获取数据库数据
    queryset = models.Book.objects.all()
    # 获取序列化类
    serializer_class = serializer.BookSerializer

    def get(self, request):
        """调用父类的list方法,也就是ListModelMixin中的方法"""
        return super().list(request)

    def post(self, request):
        """调用父类的create方法,也就是CreateModelMixin中的方法"""
        return super().create(request)


# 查询一个数据、修改数据、删除数据接口
class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    """重写属性"""
    # 获取数据库数据
    queryset = models.Book.objects.all()
    # 获取序列化类
    serializer_class = serializer.BookSerializer

    def get(self, request, *args, **kwargs):
        """调用父类的retrieve方法,也就是RetrieveModelMixin中的方法"""
        return super().retrieve(request, *args, **kwargs)
    
    def put(self, request, *args, **kwargs):
        """调用父类的update方法,也就是UpdateModelMixin中的方法"""
        return super().update(request, *args, **kwargs)
    
    def delete(self, request, *args, **kwargs):
        """调用父类的destroy方法,也就是DestroyModelMixin中的方法"""
        return super().destroy(request, *args, **kwargs)

现在代码是不是看起来少了一些了?这才第二层,继续往下!

视图子类

DRF提供了9个视图子类,稍微帮我们封装了一下代码。

# 提供查询所有接口
from rest_framework.generics import ListAPIView
# 提供添加单个接口
from rest_framework.generics import CreateAPIView
# 提供查询所有和添加单个接口
from rest_framework.generics import ListCreateAPIView
# 提供查询单个接口
from rest_framework.generics import RetrieveAPIView
# 提供修改单个接口
from rest_framework.generics import UpdateAPIView
# 提供删除单个接口
from rest_framework.generics import DestroyAPIView
# 提供查询单个和修改单个接口
from rest_framework.generics import RetrieveUpdateAPIView
# 提供查询单个和删除单个接口
from rest_framework.generics import RetrieveDestroyAPIView
# 提供查询单个和修改单个和删除单个接口
from rest_framework.generics import RetrieveUpdateDestroyAPIView

这9个视图子类仅仅只帮我们做了个封装,之后我们编写CBV时去继承这9个试图子类。

image

CBV使用(第三层)

from rest_framework.generics import RetrieveUpdateDestroyAPIView
from rest_framework.generics import ListCreateAPIView
# 查询所有数据、添加数据接口
class BookView(ListCreateAPIView):
    """重写属性"""
    # 获取数据库数据
    queryset = models.Book.objects.all()
    # 获取序列化类
    serializer_class = serializer.BookSerializer

# 查询一个数据、修改数据、删除数据接口
class BookDetailView(RetrieveUpdateDestroyAPIView):
    """重写属性"""
    # 获取数据库数据
    queryset = models.Book.objects.all()
    # 获取序列化类
    serializer_class = serializer.BookSerializer

现在是不是代码量骤降?现在才第三层,下面还有!

视图集

视图集,顾名思义,就是视图的集合。

DRF视图集中主要有五个类:

from rest_framework.viewsets import ViewSetMixin
from rest_framework.viewsets import ViewSet
from rest_framework.viewsets import GenericViewSet
from rest_framework.viewsets import ModelViewSet
from rest_framework.viewsets import ReadOnlyModelViewSet

ViewSetMixin类

主要提供了一个不一样的as_view()方法,让我们可以在路由层做一些映射关系。

ViewSet类

继承了ViewSetMiXin类和APIView类。

GenericViewSet类

继承了ViewSetMiXin类和GenericAPIView类

ModelViewSet类

继承了ViewSetMixin类和5个视图拓展类,拥有了list、retrieve、update、create、destroy方法。

image

ReadOnlyModelViewSet类

继承了ViewSetMixin类和2个视图拓展类,拥有了list、retrieve方法。

image

CBV使用(第四层)

from rest_framework.viewsets import ModelViewSet

class BookView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookSerializer

因为没有请求方法的编写,所以我们要去路由层添加映射关系:

# 路由层
urlpatterns = [
    path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
    path('books/<int:pk>', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]

我们甚至可以给CBV添加除请求方法以外的函数:

from rest_framework.viewsets import ModelViewSet

class BookView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializer.BookSerializer
    
    def login(self, request):
        return Response('login')

路由层:

# 路由层
urlpatterns = [
    path('books/', views.BookView.as_view({'get': 'login'})),
]

这样就会在浏览器发送get请求时执行视图类中的login方法。

视图类继承图

image

ViewSetMixin类解析

ViewSetMixin类提供了一个新的as_view()方法,我们可以查看源码看看具体是怎么实现的。

image

首先提供了一个actions参数,用于接收映射关系。

其次是下面图片中的红框部分。

image

假设在路由配置了如下映射:

as_view({'get': 'list', 'post': 'create'})

这时acitons的值为:

{'get': 'list', 'post': 'create'}

图片红框部分遍历了actions:

# 遍历actions
for method, action in actions.items():
    """
    method的值依次为:get、post
    action的值依次为:list、create
    """
    # 先获取list、create方法
    handler = getattr(self, action)
    # 通过反射将get方法映射成list方法...
    setattr(self, method, handler)
posted @ 2022-06-17 19:07  Yume_Minami  阅读(236)  评论(0编辑  收藏  举报