DRF 过滤

DRF 过滤

Manager提供的根QuerySet描述数据库表中的所有对象。但是,通常,您只需要选择整个对象集的子集。

REST框架默认情况下返回整个 model 查询集合,通常情况下,我们需要限制查询集返回的项目。

  1. 直接在view中写过滤(其实DRF中的过滤也是在view中调用方法实现过滤)
  2. 覆盖.get_queryset方式实现过滤,如果view继承GenericAPIView
  3. 使用DRF过滤器
  4. 自定义过滤器
  5. 如果需要对序列化后的数据过滤,那么只能在view中过滤了

直接在view中写过滤

    def get(self, request, *args, **kwargs):
        res_obj = BaseResponse()

        try:
            queryset = self.filter_queryset(self.get_queryset())
            # 手动过滤
            # 拿到过滤的条件
            course_category_id = request.query_params.get('sub_category', '')
            if course_category_id != '0' and course_category_id.isdigit():
            	queryset = queryset.filter(course_category_id=course_category_id)

            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)
            res_obj.data = serializer.data
        except Exception as e:
            res_obj.code = 1
            res_obj.msg = str(e)
        return Response(res_obj.dict)

覆盖.get_queryset方式实现过滤,如果view继承GenericAPIView

from rest_framework import filters

class UserListView(generics.ListAPIView):
   queryset = User.objects.all()
   serializer_class = UserSerializer
   filter_backends = (filters.SearchFilter,)
   search_fields = ('username', 'email')

使用DRF过滤器

DjangoFilterBackend

django-filter库包含一个DjangoFilterBackend类,该类支持REST框架的高度可定制的字段过滤。

要使用DjangoFilterBackend,请先安装django-filter。然后添加django_filters到Django的INSTALLED_APPS

全局配置

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

局部配置

from django_filters.rest_framework import DjangoFilterBackend

class UserListView(generics.ListAPIView):
    ...
    filter_backends = (DjangoFilterBackend,)

自定义过滤器

view

class CourseListView(ListAPIView):
    queryset = models.Course.objects.all()
    serializer_class = CourseModelSerializer
    filter_backends = [MyFilter, ]  # 使用自定义的filter 

    def get(self, request, *args, **kwargs):
        res_obj = BaseResponse()

        try:
            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)
            res_obj.data = serializer.data
        except Exception as e:
            res_obj.code = 1
            res_obj.msg = str(e)
        return Response(res_obj.dict)

filer

class MyFilter(BaseFilterBackend):

    def filter_queryset(self, request, queryset, view):
        course_category_id = request.query_params.get('sub_category', '')
        if course_category_id != '0' and course_category_id.isdigit():
            queryset = queryset.filter(course_category_id=course_category_id)

        return queryset

对序列化后的数据过滤,只能在view中过滤

view

class CourseListView(ListAPIView):
    queryset = models.Course.objects.all()
    serializer_class = CourseModelSerializer
    filter_backends = [MyFilter, ]

    def get(self, request, *args, **kwargs):
        res_obj = BaseResponse()

        try:
            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)
            # 因为要排序的字段是我们序列化的时候自己加的字段,不能使用内置的order_by
            data: list = serializer.data
            # 拿到需要排序字段
            ordering_key: str = request.query_params.get('ordering')
            if ordering_key:
                if ordering_key.startswith('-'):
                    ordering_key = ordering_key[1:]
                    is_reverse = True
                elif ordering_key == 'learn_number':
                    is_reverse = True
                else:
                    is_reverse = False
                data.sort(key=lambda item: item.get(ordering_key), reverse=is_reverse)

            res_obj.data = data
        except Exception as e:
            res_obj.code = 1
            res_obj.msg = str(e)
        return Response(res_obj.dict)

源码分析

分析 ListAPIView 实现的过滤

ListAPIView ——》get方法 ——》ListModelMixin 中的 list 方法——》self.filter_queryset(self.get_queryset()) 执行GenericAPIView 中的 filter_queryset 方法——》实例化 过滤器并执行 filter_queryset 方法 返回 queryset

1562470291871

1562470405907

1562470530844

posted @ 2019-08-16 16:37  写bug的日子  阅读(420)  评论(0编辑  收藏  举报