drf 中的ListAPIView视图

2019-12-18  本文已影响0人  evday

写一个类继承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'
}
上一篇下一篇

猜你喜欢

热点阅读