Filter
基本使用
#settings
INSTALLED_APPS = [
...
'django_filters'
]
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}
#view.py:
class myfilter(Modelviewset):
queryset = models.NBUserInfo.objects.all()
serializer_class = GenericsSerializer
#指定过滤字段
filterset_fields = ['gender','name']
通过http://127.0.0.1:8000/api/myfilter?gender=1&name=hg
接口后缀加?加需要筛选的字段值惊醒筛选
源码流程
class filter(Modelviewset):
...
class ModelViewSet( ...
mixins.ListModelMixin,
GenericViewSet):
...
#过滤的功能是由ListModelMixin携带的
class ListModelMixin:
def list(self, request, *args, **kwargs):
#filter_queryset会寻找到父类GenericViewSet的父类GenericAPIView
#queryset获取到的是需要过滤的字段
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)
class GenericAPIView(views.APIView):
def get_queryset(self):
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()
return queryset #返回queryset.all()
def filter_queryset(self, queryset):
for backend in list(self.filter_backends): #循环获取filter_backends
#实例化backend,调用实例化backend的filter_queryset方法
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
class DjangoFilterBackend:
filterset_base = filterset.FilterSet
def filter_queryset(self, request, queryset, view):
#获取过滤类
filterset = self.get_filterset(request, queryset, view)
if filterset is None:
return queryset
if not filterset.is_valid() and self.raise_exception:
raise utils.translate_validation(filterset.errors)
return filterset.qs
def get_filterset(self, request, queryset, view):
#调用get_filterset_class获取filterset_class和filterset_fields
filterset_class = self.get_filterset_class(view, queryset)
if filterset_class is None:
return None
def get_filterset_class(self, view, queryset=None):
"""
Return the `FilterSet` class used to filter the queryset.
"""
filterset_class = getattr(view, "filterset_class", None)
filterset_fields = getattr(view, "filterset_fields", None)
if filterset_class:
filterset_model = filterset_class._meta.model
# FilterSets do not need to specify a Meta class
if filterset_model and queryset is not None:
assert issubclass(
queryset.model, filterset_model
), "FilterSet model %s does not match queryset model %s" % (
filterset_model,
queryset.model,
)
return filterset_class
#filterset_fields是在视图对象中定义的过滤字段,queryset是视图中定义的queryset
if filterset_fields and queryset is not None:
MetaBase = getattr(self.filterset_base, "Meta", object)
#使用django-filter的方法获取包含过滤的queryset对象
class AutoFilterSet(self.filterset_base):
class Meta(MetaBase):
model = queryset.model
fields = filterset_fields
#返回一个AutoFilterSet对象,包含合法的过滤字段
return AutoFilterSet
return None
流程
ListModelMixin的list方法-->调用GenericAPIView声明的filter_queryset方法-->全局或局部配置的filter_backends声明的filter_queryset方法-->调用django-filter-->返回queryset对象。
Ordering
基本使用
#setting
'''
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.OrderingFilter'
]
'''
#views.py
from rest_framework import filters
class filter(Modelviewset):
#ordering和filter用的是同一个配置名,也可以在setting做全局配置
filter_backends = [DjangoFilterBackend,filters.OrderingFilter,]
#如果是用元组要在最后加上,!!!!!
ordering_fields = ['id']
'''
路由地址:
http://127.0.0.1:8000/api/filter/?ordering=-id
多字段排序
http://127.0.0.1:8000/api/filter/?ordering=age,-id
排序加过滤
http://127.0.0.1:8000/api/filter/?ordering=gender,-id&gender=2
'''
过滤组件和排序组件一个全局一个局部会出现不能排序或过滤的bug,因此这两个组件一般使用局部的写法