首页 > 其他分享 >DRF的filter组件

DRF的filter组件

时间:2023-04-23 11:22:54浏览次数:35  
标签:serializers level models age class filter 组件 id DRF

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 '\'
    

标签:serializers,level,models,age,class,filter,组件,id,DRF
From: https://www.cnblogs.com/huxiaofeng1029/p/17345947.html

相关文章

  • 【快应用】表单组件的model属性实际运用
     【关键词】表单组件、model 【问题背景】在使用表单组件时,往往需要同时绑定值和 change 事件动态更新数据,当表单交互较多的场景下会有大量与业务无关的代码。快应用从1100版本开始引入 model 指令,使用 model 指令可以简化代码逻辑,在框架内部对值进行绑定与更新,实现......
  • SpringSecurity过滤器之HeaderWriterFilter
    HeaderWriterFilter用于对当前的HttpServletResponse添加某些浏览器保护的响应头。HeaderWriterFilter由HeadersConfigurer配置,在执行HeadersConfigurer#configure时调用createHeaderWriterFilter创建HeaderWriterFilter,同时添加了HeaderWriter集合:privateList<HeaderWriter>ge......
  • SpringSecurity过滤器之ExceptionTranslationFilter
    ExceptionTranslationFilter是处理AuthenticationException(身份认证异常)和AccessDeniedException(权限异常)。ExceptionTranslationFilter用法和源码分析参考一文搞定SpringSecurity异常处理机制!。 AuthenticationEntryPoint是处理AuthenticationException,默认实现是LoginUrl......
  • react18中antd的Upload组件上传头像,并且拿到服务器返回的头像的url地址在页面中显示头
    业务需求:上传头像,上传完毕后拿到头像的url,把头像展示在页面中,最终把头像url和其他用户信息一起发送给服务器 上传头像流程 导入Upload组件和图标(一个加号,一个加载中)import{Upload}from'antd';import{PlusOutlined,LoadingOutlined}from'@ant-design/ic......
  • toga高级组件
    Toga还提供了一些高级组件,如表格、滚动容器等,以满足更复杂的应用需求。以下是一些常用的高级组件的介绍和使用方法:表格-toga.Tabletoga.Table用于创建一个表格控件,用于显示数据。常用参数:id:表格控件的唯一标识符。data:表格的数据,格式为二维数组。headings:表格的标题,格式为......
  • 微信小程序:uni-app页面Page和组件Component生命周期执行的先后顺序
    目录H5微信小程序测试代码文档页面生命周期https://uniapp.dcloud.net.cn/tutorial/page.html#lifecycle组件生命周期https://uniapp.dcloud.net.cn/tutorial/page.html#componentlifecycle经测试,得出结论:H5和微信小程序的生命周期函数调用顺序不一致H5pagebeforeCreatepag......
  • vscode中react组件
    title:"vscode中ES7+React/Redux/React-Nativesnippets插件使用"date:2023-04-0723:21:32tags:['Vscode','插件']categories:["工具篇"]通过使用这个插件我们可以很方便的进行组件/方法/文件的导入本篇博客仅对插件进行介绍翻译,便于自己以后使用常用片段列表imr:......
  • vue组件
    vue组件实际上就是自定义标签组件是vue可重复使用的实例也就是说,当你定义好一个组件之后,你可以将其当做一个html的标签使用<divid="app"><br><qinjiang></qinjiang><br></div><divid="buttonnew"><newbutton></newbutton>......
  • Vue:表单双绑、组件
    vue一大精髓就是双向绑定vue.js是一个mvvm框架,即数据的双向绑定,即当数据发生变化时的时候,视图也就发生变化,当视图发生变化时,数据也会同步变化双向绑定是对于UI控件来说的,非UI控件不会涉及到数据的双向绑定以input标签举例<divid="app">输入的文本:<inputtype="text"v-......
  • drf之多表关联反序列化保存read_only与write_only
    目录read_only与write_only示例假如前端传入了一组数据:{name:'赛尔达传说:王国之泪',price:350,publish:1,authors:[1,2]}如上:publish按id传入,authors也按id传入。read_only与write_onlyread_only用于序列化write_only用于反序列化这两个是字段参数示例#......