DRF 过滤
DRF 过滤
Manager提供的根QuerySet描述数据库表中的所有对象。但是,通常,您只需要选择整个对象集的子集。
REST框架默认情况下返回整个 model 查询集合,通常情况下,我们需要限制查询集返回的项目。
- 直接在view中写过滤(其实DRF中的过滤也是在view中调用方法实现过滤)
- 覆盖
.get_queryset
方式实现过滤,如果view继承GenericAPIView
- 使用DRF过滤器
- 自定义过滤器
- 如果需要对序列化后的数据过滤,那么只能在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过滤器
该
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