• DRF的filter组件


    DRF的Filter组件

    如果某个API需要传递一些条件进行搜索,其实就在是URL后面通过GET传参即可,例如:

    /api/users?age=19&category=12
    

    在drf中filter组件可以支持条件搜索。

    1. 自定义filter

    # models.py
    from django.db import models
    
    
    class Role(models.Model):
        """ 角色表 """
        title = models.CharField(verbose_name='名称', max_length=32)
    
    
    class Department(models.Model):
        """ 部门表 """
        title = models.CharField(verbose_name='名称', max_length=32)
    
    
    class UserInfo(models.Model):
        username = models.CharField(verbose_name='用户名', max_length=32)
        age = models.CharField(verbose_name='年龄', max_length=32)
        level_choice = ((1, 'VIP'), (2, 'SVIP'), (3, 'PARTNER'))
        level = models.SmallIntegerField(verbose_name='级别', choices=level_choice)
        email = models.CharField(verbose_name='邮箱', max_length=32)
    
        # 创建外键
        depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE)
    
        # 多对多
        roles = models.ManyToManyField(verbose_name="角色", to="Role")
    
    # views.py
    from rest_framework import serializers
    from rest_framework.filters import BaseFilterBackend
    from rest_framework.viewsets import ModelViewSet
    
    from api import models
    
    
    # Create your views here.
    class UserSerializer(serializers.ModelSerializer):
        level_text = serializers.CharField(source="get_level_display", read_only=True)
        extra = serializers.SerializerMethodField(read_only=True)
    
        class Meta:
            model = models.UserInfo
            fields = ['username', 'age', 'email', "level_text", 'extra']
    
        def get_extra(self, obj):
            return '我是多余的'
    
    
    # 自定义Filter
    class Filter1(BaseFilterBackend):
        def filter_queryset(self, request, queryset, view):
            age = request.GET.get('age')  # 可以使用request.query_params
            if not age:
                return queryset
            return queryset.filter(age=age)
    
    
    class Filter2(BaseFilterBackend):
        def filter_queryset(self, request, queryset, view):
            id = request.query_params.get('id')
            if not id:
                return queryset
            return queryset.filter(id=id)
    
    
    class UserView(ModelViewSet):
        filter_backends = [Filter1, Filter2]  # 加入需要传递的Filter
        queryset = models.UserInfo.objects.all()  # GenericAPIView这个类提供的变量
        serializer_class = UserSerializer
    
    

    返回值:

    源码流程

    2. 第三方filter(常用)

    在drf开发中有一个常用的第三方过滤器:DjangoFilterBackend。

    pip install django-filter
    

    注册app:

    INSTALLED_APPS = [
        ...
        'django_filters',
        ...
    ]
    

    示例1: 简单

    视图配置和应用:

    # views.py
    from rest_framework import serializers
    from rest_framework.viewsets import ModelViewSet
    from django_filters.rest_framework import DjangoFilterBackend
    from app01 import models
    
    
    class UserModelSerializer(serializers.ModelSerializer):
        level_text = serializers.CharField(
            source="get_level_display",
            read_only=True
        )
        extra = serializers.SerializerMethodField(read_only=True)
    
        class Meta:
            model = models.UserInfo
            fields = ["username", "age", "email", "level_text", "extra"]
    
        def get_extra(self, obj):
            return 666
    
    
    class UserView(ModelViewSet):
        filter_backends = [DjangoFilterBackend, ]
        filterset_fields = ["id", "age", "email"]
    
        queryset = models.UserInfo.objects.all()
        serializer_class = UserModelSerializer
    
        def perform_create(self, serializer):
            """ 序列化:对请求的数据校验成功后,执行保存。"""
            serializer.save(depart_id=1, password="123")
    
    

    示例2: 复杂

    视图配置和应用(示例3):

    from rest_framework import serializers
    from rest_framework.viewsets import ModelViewSet
    from django_filters.rest_framework import DjangoFilterBackend, OrderingFilter
    from django_filters import FilterSet, filters
    from app01 import models
    
    
    class UserModelSerializer(serializers.ModelSerializer):
        level_text = serializers.CharField(
            source="get_level_display",
            read_only=True
        )
        depart_title = serializers.CharField(
            source="depart.title",
            read_only=True
        )
        extra = serializers.SerializerMethodField(read_only=True)
    
        class Meta:
            model = models.UserInfo
            fields = ["id", "username", "age", "email", "level_text", "extra", "depart_title"]
    
        def get_extra(self, obj):
            return 666
    
    
    class MyFilterSet(FilterSet):
        # /api/users/?min_id=2  -> id>=2
        min_id = filters.NumberFilter(field_name='id', lookup_expr='gte')
    
        # /api/users/?name=wupeiqi  -> not ( username=wupeiqi )
        name = filters.CharFilter(field_name="username", lookup_expr="exact", exclude=True)
    
        # /api/users/?depart=xx     -> depart__title like %xx%
        depart = filters.CharFilter(field_name="depart__title", lookup_expr="contains")
    
        # /api/users/?token=true      -> "token" IS NULL
        # /api/users/?token=false     -> "token" IS NOT NULL
        token = filters.BooleanFilter(field_name="token", lookup_expr="isnull")
    
        # /api/users/?email=xx     -> email like xx%
        email = filters.CharFilter(field_name="email", lookup_expr="startswith")
    
        # /api/users/?level=2&level=1   -> "level" = 1 OR "level" = 2(必须的是存在的数据,否则报错-->内部有校验机制)
        # level = filters.AllValuesMultipleFilter(field_name="level", lookup_expr="exact")
        level = filters.MultipleChoiceFilter(field_name="level", lookup_expr="exact", choices=models.UserInfo.level_choices)
    
        # /api/users/?age=18,20     -> age in [18,20]
        age = filters.BaseInFilter(field_name='age', lookup_expr="in")
    
        # /api/users/?range_id_max=10&range_id_min=1    -> id BETWEEN 1 AND 10
        range_id = filters.NumericRangeFilter(field_name='id', lookup_expr='range')
    
        # /api/users/?ordering=id     -> order by id asc
        # /api/users/?ordering=-id     -> order by id desc
        # /api/users/?ordering=age     -> order by age asc
        # /api/users/?ordering=-age     -> order by age desc
        ordering = filters.OrderingFilter(fields=["id", "age"])
    
        # /api/users/?size=1     -> limit 1(自定义搜索)
        size = filters.CharFilter(method='filter_size', distinct=False, required=False)
        
        class Meta:
            model = models.UserInfo
            fields = ["id", "min_id", "name", "depart", "email", "level", "age", 'range_id', "size", "ordering"]
    
        def filter_size(self, queryset, name, value):
            int_value = int(value)
            return queryset[0:int_value]
    
    
    class UserView(ModelViewSet):
        filter_backends = [DjangoFilterBackend, ]
        filterset_class = MyFilterSet
    
        queryset = models.UserInfo.objects.all()
        serializer_class = UserModelSerializer
    
        def perform_create(self, serializer):
            """ 序列化:对请求的数据校验成功后,执行保存。"""
            serializer.save(depart_id=1, password="123")
    
    

    补充

    lookup_expr有很多常见选择:

    'exact': _(''),
    'iexact': _(''),
    
    'contains': _('contains'),
    'icontains': _('contains'),
    'startswith': _('starts with'),
    'istartswith': _('starts with'),
    'endswith': _('ends with'),  
    'iendswith': _('ends with'),
        
    'gt': _('is greater than'),
    'gte': _('is greater than or equal to'),
    'lt': _('is less than'),
    'lte': _('is less than or equal to'),
    
    'in': _('is in'),
    'range': _('is in range'),
    'isnull': _(''),
        
    'regex': _('matches regex'),
    'iregex': _('matches regex'),
    

    全局配置和应用:

    # settings.py 全局配置
    
    REST_FRAMEWORK = {
        'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend',]
    }
    

    3. 内置filter

    drf源码中内置了2个filter,分别是:

    • OrderingFilter,支持排序。

      from rest_framework import serializers
      from rest_framework.viewsets import ModelViewSet
      from app01 import models
      from rest_framework.filters import OrderingFilter
      
      
      class UserModelSerializer(serializers.ModelSerializer):
          level_text = serializers.CharField(
              source="get_level_display",
              read_only=True
          )
          depart_title = serializers.CharField(
              source="depart.title",
              read_only=True
          )
          extra = serializers.SerializerMethodField(read_only=True)
      
          class Meta:
              model = models.UserInfo
              fields = ["id", "username", "age", "email", "level_text", "extra", "depart_title"]
      
          def get_extra(self, obj):
              return 666
      
      
      class UserView(ModelViewSet):
          filter_backends = [OrderingFilter, ]
          # ?order=id
          # ?order=-id
          # ?order=age
          ordering_fields = ["id", "age"]
      
          queryset = models.UserInfo.objects.all()
          serializer_class = UserModelSerializer
      
          def perform_create(self, serializer):
              """ 序列化:对请求的数据校验成功后,执行保存。"""
              serializer.save(depart_id=1, password="123")
      
    • SearchFilter,支持模糊搜索。

      from rest_framework import serializers
      from rest_framework.viewsets import ModelViewSet
      from app01 import models
      from rest_framework.filters import SearchFilter
      
      
      class UserModelSerializer(serializers.ModelSerializer):
          level_text = serializers.CharField(
              source="get_level_display",
              read_only=True
          )
          depart_title = serializers.CharField(
              source="depart.title",
              read_only=True
          )
          extra = serializers.SerializerMethodField(read_only=True)
      
          class Meta:
              model = models.UserInfo
              fields = ["id", "username", "age", "email", "level_text", "extra", "depart_title"]
      
          def get_extra(self, obj):
              return 666
      
      
      class UserView(ModelViewSet):
          filter_backends = [SearchFilter, ]
          search_fields = ["id", "username", "age"]
      
          queryset = models.UserInfo.objects.all()
          serializer_class = UserModelSerializer
      
          def perform_create(self, serializer):
              """ 序列化:对请求的数据校验成功后,执行保存。"""
              serializer.save(depart_id=1, password="123")
      
      
      "app01_userinfo"."id" LIKE %18% ESCAPE '\' 
      OR 
      "app01_userinfo"."username" LIKE %18% ESCAPE '\' 
      OR 
      "app01_userinfo"."age" LIKE %18% ESCAPE '\'
      
  • 相关阅读:
    vector
    用JavaScript输出0-9的两种方法、以及setTimeout的三个参数的意义
    企业数字化转型资料合集
    LeetCode --- 2. Add Two Numbers 解题报告
    NPM不想来回切换私有源
    Oracle EBS 导入日记账提示警告 GL_INTERFACE 错误代码ECW1,EC11
    C++:多态
    [附源码]计算机毕业设计springboot青栞系统
    LaTex生成引文(参考文献)时出现乱序,想把引文按顺序显示的解决方法
    AVR单片机及其编译软件
  • 原文地址:https://www.cnblogs.com/huxiaofeng1029/p/17345947.html