美文网首页
drf 中的ListAPIView视图

drf 中的ListAPIView视图

作者: evday | 来源:发表于2019-12-18 21:57 被阅读0次

    写一个类继承ListAPIView返回列表数据

    class MySerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Tag
            fields = '__all__'
    
    class MyFilterBackend(BaseFilterBackend):#BaseFilterBackend的子类必须实现filter_queryset()方法
        def filter_queryset(self, request, queryset, view):
            var = request.query_params.get('category')#获取/xxx/?category=?? 参数值
            return queryset.filter(category=var)#将参数当作条件加入到queryset的filter()方法中
    
    class MyAPIView(ListAPIView):
        queryset = models.MyModel.objects
        serializer_class = MySerializer
        filter_backends = [MyFilterBackend] #可以定义多个过滤类
    

    这样就实现了返回列表数据,如何实现的,首先查看ListAPIView类,发现它只有一个get方法,调用了self.list()方法

        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    

    self.list()方法在我们自己写的MyAPIView中并没有实现,所以这时候看ListAPIView的父类,ListAPIView 有两个父类和GenericAPIView,根据继承顺序先看mixins.ListModelMixin,发现有list方法

        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)
    

    这里面调用了self.filter_queryset()方法,self.get_queryset()方法,self.paginate_queryset()方法,self.get_serializer()方法,self.get_paginated_response()方法,最终返回了列表数据,而这些方法在我们自己写的MyAPIView以及ListAPIViewmixins.ListModelMixin中都没有定义,这时候我们看ListAPIView的另一个父类

    class GenericAPIView(views.APIView):
        queryset = None  #数据源
        serializer_class = None #序列化器列表
        filter_backends = api_settings.DEFAULT_FILTER_BACKENDS #过滤器
        pagination_class = api_settings.DEFAULT_PAGINATION_CLASS #分页
    
        def get_queryset(self): #断言如果self.queryset为空会报错,所以在我们定义的视图中必须有queryset这个属性
            assert self.queryset is not None, (
                "'%s' should either include a `queryset` attribute, "
                "or override the `get_queryset()` method."
                % self.__class__.__name__
            )
            queryset = self.queryset
            if isinstance(queryset, QuerySet):
                queryset = queryset.all() #我们自己的MyAPIView 的queryset 可以不用加all(),这里会帮我们加上
            return queryset
    
        def get_serializer_class(self): #断言如果self.serializer_class为空会报错,所以在我们定义的视图中必须有serializer_class这个属性
            assert self.serializer_class is not None, (
                "'%s' should either include a `serializer_class` attribute, "
                "or override the `get_serializer_class()` method."
                % self.__class__.__name__
            )
            return self.serializer_class
    
        def get_serializer(self, *args, **kwargs):#这里实例化了我们定义的MySerializer序列化类
            serializer_class = self.get_serializer_class()
            return serializer_class(*args, **kwargs)
    
        def filter_queryset(self, queryset):
            #这里会循环过滤器列表,并分别调用他们的filter_queryset()方法对我们的queryset 做过滤,
            #如果我们没有覆盖filter_backends属性,那么就不会做任何过滤
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset
    
        @property
        def paginator(self):#这里如果我们在配置文件中指定了分页器,利用反射实例化分页类
            if not hasattr(self, '_paginator'):
                if self.pagination_class is None:
                    self._paginator = None
                else:
                    self._paginator = self.pagination_class()
            return self._paginator
       
        def paginate_queryset(self, queryset):#这里会调用分页器的paginage_querset()方法进行分页
            if self.paginator is None:
                return None
            return self.paginator.paginate_queryset(queryset, self.request, view=self)
    
        def get_paginated_response(self, data):
            #这里对分页的数据进行了一个包装,比如我们在配置文件中指定的分页类是PageNumberPagination,
            #那么会返回一个有序字典,包含count、next、previous、results 这四项内容
            assert self.paginator is not None
            return self.paginator.get_paginated_response(data)
    

    看到这里,在GenericAPIView 这个类中,将我们所有的方法都已经帮我们实现了,我们只需要定义两个属性就可以完成列表数据的展示,在settings配置文件中指定分页类就可以实现分页效果

    REST_FRAMEWORK = {
        'PAGE_SIZE':10, #每页显示的条数
        'DEFAULT_PAGINATION_CLASS':'rest_framework.pagination.PageNumberPagination'
    }
    

    相关文章

      网友评论

          本文标题:drf 中的ListAPIView视图

          本文链接:https://www.haomeiwen.com/subject/ypqpnctx.html