• Day 75 视图类/视图工具类/工具视图类/视图集


    视图家族

    视图类

    APIView和GenericAPIView

    GenericAPIView中比较重要的两个方法:

    • get_object

      • 获取单查对象
    • get_serializer

      • 获取单查对象的序列化
    from rest_framework.generics import GenericAPIView
    
    class CarGenericAPIView(GenericAPIView):
        # 
        queryset = models.Car.objects.filter(is_delete=False).all()
        serializer_class = serializers.CarModelSerializer
        lookup_url_kwarg = 'pk'
        def get(self, request, *args, **kwargs):
            car_obj = self.get_object()
            car_ser = self.get_serializer(car_obj)
            return APIResponse(results=car_ser.data)
    

    GenericAPIView中query_set默认为None,需要自己进行赋值

    注: models.Car.objects 是Manager对象,管理QuerySet

    Mixins视图工具类

    必须配合GenericAPIView类使用,将单查, 群查, 单增, 整体/局部单改, 单删留个接口封装成retrieve, list, create, update, partial_update, destroy六个方法

    原因: 六个方法的实现体,调用的方法就是GenericAPIView提供的

    • ListModelMixin

      群查功能源码

      class ListModelMixin:
          """
          List a queryset.
          """
          def list(self, request, *args, **kwargs):
              queryset = self.filter_queryset(self.get_queryset())
      
              page = self.paginate_queryset(queryset)
              if page is not None:
                  serializer = self.get_serializer(page, many=True)
                  return self.get_paginated_response(serializer.data)
      
              serializer = self.get_serializer(queryset, many=True)
              return Response(serializer.data)
      
    • RetrieveModelMixin

      单查功能源码

      class RetrieveModelMixin:
          """
          Retrieve a model instance.
          """
          def retrieve(self, request, *args, **kwargs):
              instance = self.get_object()
              serializer = self.get_serializer(instance)
              return Response(serializer.data)
      
    • CreateModelMixin

      单增功能源码

      class CreateModelMixin:
          """
          Create a model instance.
          """
          def create(self, request, *args, **kwargs):
              serializer = self.get_serializer(data=request.data)
              serializer.is_valid(raise_exception=True)
              self.perform_create(serializer)
              headers = self.get_success_headers(serializer.data)
              return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
      
          def perform_create(self, serializer):
              serializer.save()
      
          def get_success_headers(self, data):
              try:
                  return {'Location': str(data[api_settings.URL_FIELD_NAME])}
              except (TypeError, KeyError):
                  return {}
      
    • DestroyModelMixin

      单删功能源码

      class DestroyModelMixin:
          """
          Destroy a model instance.
          """
          def destroy(self, request, *args, **kwargs):
              instance = self.get_object()
              self.perform_destroy(instance)
              return Response(status=status.HTTP_204_NO_CONTENT)
      
          def perform_destroy(self, instance):
              instance.delete()
      
    • UpdateModelMixin

      整体或局部单改功能源码

      class UpdateModelMixin:
          """
          Update a model instance.
          """
          def update(self, request, *args, **kwargs):
              partial = kwargs.pop('partial', False)
              instance = self.get_object()
              serializer = self.get_serializer(instance, data=request.data, partial=partial)
              serializer.is_valid(raise_exception=True)
              self.perform_update(serializer)
      
              if getattr(instance, '_prefetched_objects_cache', None):
                  # If 'prefetch_related' has been applied to a queryset, we need to
                  # forcibly invalidate the prefetch cache on the instance.
                  instance._prefetched_objects_cache = {}
      
              return Response(serializer.data)
      
          def perform_update(self, serializer):
              serializer.save()
      
          def partial_update(self, request, *args, **kwargs):
              kwargs['partial'] = True
              return self.update(request, *args, **kwargs)
      

      视图工具类的使用

      from rest_framework.mixins import RetrieveModelMixin, ListModelMixin, CreateModelMixin
      class CarReadCreateGenericAPIView(ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericAPIView):
          queryset = models.Car.objects.filter(is_delete=False).all()
          serializer_class = serializers.CarModelSerializer
          lookup_url_kwarg = 'pk'
          # 群查
          # """
          def get(self, request, *args, **kwargs):
              # car_query = self.get_queryset()
              # car_ser = self.get_serializer(car_query, many=True)
              # return APIResponse(results=car_ser.data)
              return self.list(request, *args, **kwargs)
          # """
      
          # 单查
          """
          def get(self, request, *args, **kwargs):
              # car_obj = self.get_object()
              # car_ser = self.get_serializer(car_obj)
              # return APIResponse(results=car_ser.data)
              response = self.retrieve(request, *args, **kwargs)
              return APIResponse(results=response.data)
          """
      
          # 单增
          def post(self, request, *args, **kwargs):
              return self.create(request, *args, **kwargs)
      

    Generic工具视图类

    工具视图类就是将不同种类的mixins与GenericAPIView进行组合,一共有9个类(九种组合)

    (单查群查不能在一起)

    只需要我们配置三个类属性即可: queryset, serializer_class, lookup_url_kwarg

    • CreateAPIView

      class CreateAPIView(mixins.CreateModelMixin,
                          GenericAPIView):
          def post(self, request, *args, **kwargs):
              return self.create(request, *args, **kwargs)
      
    • ListAPIView

      class ListAPIView(mixins.ListModelMixin,
                        GenericAPIView):
          def get(self, request, *args, **kwargs):
              return self.list(request, *args, **kwargs)
      
    • RetrieveAPIView

      class RetrieveAPIView(mixins.RetrieveModelMixin,
                            GenericAPIView):
          def get(self, request, *args, **kwargs):
              return self.retrieve(request, *args, **kwargs)
      
    • DestroyAPIView

      class DestroyAPIView(mixins.DestroyModelMixin,
                           GenericAPIView):
          def delete(self, request, *args, **kwargs):
              return self.destroy(request, *args, **kwargs)
      
    • UpdateAPIView

      class UpdateAPIView(mixins.UpdateModelMixin,
                          GenericAPIView):
          def put(self, request, *args, **kwargs):
              return self.update(request, *args, **kwargs)
      
          def patch(self, request, *args, **kwargs):
              return self.partial_update(request, *args, **kwargs)
      
    • ListCreateAPIView

      class ListCreateAPIView(mixins.ListModelMixin,
                              mixins.CreateModelMixin,
                              GenericAPIView):
          def get(self, request, *args, **kwargs):
              return self.list(request, *args, **kwargs)
      
          def post(self, request, *args, **kwargs):
              return self.create(request, *args, **kwargs)
      
    • RetrieveUpdateAPIView

      class RetrieveUpdateAPIView(mixins.RetrieveModelMixin,
                                  mixins.UpdateModelMixin,
                                  GenericAPIView):
          def get(self, request, *args, **kwargs):
              return self.retrieve(request, *args, **kwargs)
      
          def put(self, request, *args, **kwargs):
              return self.update(request, *args, **kwargs)
      
          def patch(self, request, *args, **kwargs):
              return self.partial_update(request, *args, **kwargs)
      
    • RetrieveDestroyAPIView

      class RetrieveDestroyAPIView(mixins.RetrieveModelMixin,
                                   mixins.DestroyModelMixin,
                                   GenericAPIView):
          def get(self, request, *args, **kwargs):
              return self.retrieve(request, *args, **kwargs)
      
          def delete(self, request, *args, **kwargs):
              return self.destroy(request, *args, **kwargs)
      
    • RetrieveUpdateDestroyAPIView

      class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
                                         mixins.UpdateModelMixin,
                                         mixins.DestroyModelMixin,
                                         GenericAPIView):
          def get(self, request, *args, **kwargs):
              return self.retrieve(request, *args, **kwargs)
      
          def put(self, request, *args, **kwargs):
              return self.update(request, *args, **kwargs)
      
          def patch(self, request, *args, **kwargs):
              return self.partial_update(request, *args, **kwargs)
      
          def delete(self, request, *args, **kwargs):
              return self.destroy(request, *args, **kwargs)
      

    视图集

    核心: 视图集都继承了 ViewSetMixin 类,该类重写了as_view方法,相比APIView的as_view方法,额外多出了参数actions(解决如单查群查能放在同一个类中的问题)

    • ViewSet

      该分支满足的接口与资源Model类关系不是特别密切:登录接口, 短信验证码接口

    • GenericViewSet

      该分支严格满足资源接口,与数据库进行交互

    • ModelViewSet

      能满足六大接口,只需要提供两个类属性

    • ReadOnlyModelViewSet

      只满足单查群查接口

    视图集产生的问题

    1. 没有群增,群整体改,群局部改,群删四个接口
    2. 删除操作视图集默认走的detroy方法是将资源从数据库中删除,通常是做一个字段is_delete字段修改表示删除
    3. 响应的结构只有数据,没有数据状态码和状态信息

    解决:

    class CarModelViewSet(ModelViewSet):
        queryset = models.Car.objects.filter(is_delete=False).all()
        serializer_class = serializers.CarModelSerializer
        # 分析:从实际开发角度分析不合理点
        # 1)没有群增,群整体改,群局部改,群删四个接口
        # 2)删除操作视图集默认走的destroy方法是将资源从数据库中删除,通常一个做字段is_delete字段修改表示删除
        # 3)响应的结果只有数据,没有数据状态码和状态信息
    
        # 解决1,
        # 群整体改,群局部改,全删三个接口可以独立成三个方法
        def many_update(self, request, *args, **kwargs):
            request_data = request.data
            try:
                pks = []
                for dic in request_data:
                    pk = dic.pop('pk')
                    pks.append(pk)
                book_query = models.Car.objects.filter(is_delete=False, pk__in=pks).all()
                if len(pks) != len(book_query):
                    raise Exception('pk对应的数据不存在')
            except Exception as e:
                return Response({'detail': '%s' % e}, status=400)
    
            car_ser = self.get_serializer(instance=book_query, data=request_data, many=True)
    
            car_ser.is_valid(raise_exception=True)
            car_list = car_ser.save()
            return APIResponse(results=self.get_serializer(car_list, many=True).data)
        
        def many_partial_update(self, request, *args, **kwargs):
            return APIResponse(msg='这个地方是群局部改,你会写!')
        
        def many_destroy(self, request, *args, **kwargs):
            return APIResponse(msg='这个地方是群删,你会写!')
        # 群增与单增必须公用一个接口,都要走create方法 - 重写create方法,用逻辑进行拆分
        def create(self, request, *args, **kwargs):
            request_data = request.data
            if isinstance(request_data, list):
                car_ser = self.get_serializer(data=request_data, many=True)
                car_ser.is_valid(raise_exception=True)
                car_obj = car_ser.save()
                return APIResponse(msg='群增成功', results=self.get_serializer(car_obj, many=True).data)
    
            return super().create(request, *args, **kwargs)
    
    
        # 解决2,destroy方法是完成is_delete字段值修改 - 重写destroy方法,自定义实现体
        def destroy(self, request, *args, **kwargs):
            car_obj = self.get_object()
            car_obj.is_delete = True
            car_obj.save()
            return APIResponse(msg='删除成功')
    
    
        # 解决3,让群查有状态码和状态信息 - 重写list方法
        def list(self, request, *args, **kwargs):
            response = super().list(request, *args, **kwargs)
            return APIResponse(results=response.data) 
    
  • 相关阅读:
    java通过ST4使用模板字符串
    使用 docker创建redis实例并且连接
    Docker 认证成功后还是无法push构建好的镜像
    记录一次在openwrt中折腾docker
    全局模式、PAC模式、直连模式的区别
    Vue Router中调用this.$router.push() 时,location使用path无法传入params
    liunx之系统
    liunx之通配符&正则表达式
    liunx之基础
    liunx之find命令
  • 原文地址:https://www.cnblogs.com/2222bai/p/12122938.html
Copyright © 2020-2023  润新知