DRF-django_restframework过滤组件与排序组件

85 阅读2分钟

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,因此这两个组件一般使用局部的写法