DRF框架视图类清晰整合

发布时间 2023-12-08 10:56:41作者: PiggThird

2个视图基类&5个视图mixins扩展类&9个GenericAPIView的视图子类&5个viewsets视图集基类

2个视图基类

APIView
  等级最高 但是写起来代码量也最多

# 基于APIView写的view.py
class BookView(APIView):
    def get(self, request):
        book_obj = models.Book.objects.all()
        book_ser = ser.BookModelSerializers(book_obj, many=True)
        return Response(book_ser.data)

    def post(self, request):
        book_ser = ser.BookModelSerializers(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})

  

GenericAPIView(涉及到数据库 用queryset serializer_class 比较方便) 
  1. 继承自APIVIew,

  2. 主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。

  3. 通常在使用时,可搭配一个或多个Mixin扩展类。

# 基于GenericAPIView
class Book2View(GenericAPIView):
    queryset = models.Book.objects.all()			# 获取对象
    serializer_class = ser.BookModelSerializers		 # 获取序列化对象
    def get(self, request):
        book_obj = self.get_queryset()
        book_ser = self.get_serializer(book_obj, many=True)
        return Response(book_ser.data)

    def post(self, request):
        book_ser = self.get_serializer(data=request.data)
        if book_ser.is_valid():
            book_ser.save()
            return Response(book_ser.data)
        else:
            return Response({'status': 101, 'msg': '校验失败'})

5个视图扩展类mixins

mixins介绍(CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, ListModelMixin)
  1. 提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,

  2. 如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

  3. 这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

# 一般都搭配GenericAPIView,直接继承拓展类就能实现每个方法  下面是对比
class Book3View(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = models.Book.objects.all()
    serializer_class = ser.BookModelSerializers
    # def get(self, request):
    #     book_obj = self.get_queryset()
    #     book_ser = self.get_serializer(book_obj, many=True)
    #     return Response(book_ser.data)

    def get(self, request):
        return self.list(request)

    # def post(self, request):
    #     book_ser = self.get_serializer(data=request.data)
    #     if book_ser.is_valid():
    #         book_ser.save()
    #         return Response(book_ser.data)
    #     else:
    #         return Response({'status': 101, 'msg': '校验失败'})

    def post(self, request):
        return self.create(request)

9个GenericAPIView的视图子类

GenericAPIView的子类介绍
  1. 视图子类,也叫通用视图子类。

  2. 继承了GenericAPIView,以及Mixin,真正的实现了几行代码,完成一个视图

  3. 其实就是帮你,return了视图中手动return的方法
1)CreateAPIView
 
提供 post 方法
 
继承自: GenericAPIView、CreateModelMixin
 
2)ListAPIView
 
提供 get 方法
 
继承自:GenericAPIView、ListModelMixin
 
3)RetrieveAPIView
 
提供 get 方法
 
继承自: GenericAPIView、RetrieveModelMixin
 
4)DestoryAPIView
 
提供 delete 方法
 
继承自:GenericAPIView、DestoryModelMixin
 
5)UpdateAPIView
 
提供 put 和 patch 方法
 
继承自:GenericAPIView、UpdateModelMixin
 
6)ListCreateAPIView
 
提供 get、post方法
 
继承自: GenericAPIView、ListModelMixin、CreateModelMixin

7)RetrieveUpdateAPIView
 
提供 get、put、patch方法
 
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

8)RetrieveDestroyAPIView
 
提供 get、delete方法
 
继承自: GenericAPIView、RetrieveModelMixin、DestroyModelMixin
 
9)RetrieveUpdateDestoryAPIView
 
提供 get、put、patch、delete方法
 
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

# 基于GenericAPIView的9个视图子类
# class Book4View(ListAPIView, CreateAPIView):    # 查看所有 添加一个数据
class Book4View(ListCreateAPIView):    # 两个直接并一个也可以
    queryset = models.Book.objects
    serializer_class = ser.BookModelSerializers


# class Book4DetailView(RetrieveAPIView, UpdateAPIView, DestroyAPIView):  # 查看一条数据 更新数据 删除数据
class Book4DetailView(RetrieveUpdateDestroyAPIView):  # 三个并一个也可以
    queryset = models.Book.objects
    serializer_class = ser.BookModelSerializers

5个Viewsets视图集基类

1、源码分析ViewSetMixin
# 重写了as_view
# 核心代码(所以路由中只要配置了对应关系,比如{'get':'list'}),当get请求来,就会执行list方法
for method, action in actions.items():
    # method:get
    # action:list
    handler = getattr(self, action)
    #执行完上一句,handler就变成了list的内存地址
    setattr(self, method, handler)
    #执行完上一句  对象.get=list
    #for循环执行完毕 对象.get:对着list   对象.post:对着create

2、5个Viewsets视图类
class ViewSet(ViewSetMixin, views.APIView):
    """
    The base ViewSet class does not provide any actions by default.
    """
    pass


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.
    """
    pass


class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
                           mixins.ListModelMixin,
                           GenericViewSet):
    """
    A viewset that provides default `list()` and `retrieve()` actions.
    """
    pass


class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    """
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.
    """
    pass

3、继承ViewSetMixin的视图类(可以自定义名称了,需要配置action)
# views.py方式一
from rest_framework.viewsets import ViewSetMixin
class Book6View(ViewSetMixin,APIView):
    """
    ViewSetMixin 一定要放在APIVIew前 继承的查找顺序先找前边的
    ViewSetMixin,APIView 里面都有 as_view()方法 但是我们要使用重写的as_view()方法
    所以要先去ViewSetMixin里面找
    """
    def get_all_book(self,request):
        print('我可以自定义名称喽')
        book_list = Book.objects.all()
        book_ser = BookSerializer(book_list, many=True)
        return Response(book_ser.data)    
# urls.py
    # 继承ViewSetMixin的视图类,路由可以改写成这样
    path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),


# views.py方式二
# 装饰器,放在被装饰的函数上方,method:请求方式,detail:是否带pk
from rest_framework.decorators import action    # 装饰器

class BookView(ModelViewSet):
    queryset = models.Book.objects
    serializer_class = ser.BookModelSerializer
    # methods第一个参数传入一个列表 列表中放请求方式
    # ^books/get_2/$ [name='book-get-2'] 当向这个地址发送get请求时,会执行下面的函数
    # detail 传布尔值 默认写False 当改成True时
    # ^books/(?P<pk>[^/.]+)/$ [name='book-detail'] 路由会带上pk

    @action(methods=['get'], detail=False)
    def get_2(self, request):
        book = self.get_queryset().all()[:2]
        book_ser = self.get_serializer(book, many=True)
        return Response(book_ser.data)
# urls.py
  path('books/', views.BookView.as_view(actions={'get': 'get_2'})),


# views.py方式三
class LoginView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request, *args, **kwargs):
        ser = serializer.UserSerializer(data=request.data)
        if ser.is_valid():
            token = ser.context.get('token')
            # ser.context['user']拿到的是user对象
            username = ser.context.get('user').username
            return APIResponse(token=token, username=username)
        else:
            return APIResponse(code=0, msg=ser.errors)
# urls.py 自动生成路由
from django.urls import path, re_path, include
from . import views
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
# 为什么这里不写域名 是因为你视图函数中已经定义了login这个函数他自己就传过去了 如果在写就成了/login/login
router.register('', views.LoginView, 'login')

urlpatterns = [
    path('', include(router.urls))
]


ModelViewSet了解一般不用,封装程度太高
# 基于ModelViewSet写五个接口 终极大招
path('books5/', views.Book5View.as_view(actions={'get': 'list', 'post': 'create'})),  # 当路径匹配到又是get请求 就会执行ListModelMixin方法
re_path('books5/(?P<pk>\d+)/', views.Book5View.as_view(actions={'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),

# 基于ModelViewSet写五个接口 终极大招
from rest_framework.viewsets import ModelViewSet
"""
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet)
直接继承五个大类方法  并且重写了as_view方法
"""


class Book5View(ModelViewSet):	# 一个直接写完五个接口
    queryset = models.Book.objects
    serializer_class = ser.BookModelSerializers