世界热点评!DRF的filter组件

博客园   2023-04-23 12:37:47

DRF的Filter组件

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


(相关资料图)

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

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

1. 自定义filter
# models.pyfrom django.db import modelsclass 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.pyfrom rest_framework import serializersfrom rest_framework.filters import BaseFilterBackendfrom rest_framework.viewsets import ModelViewSetfrom 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 "我是多余的"# 自定义Filterclass 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.pyfrom rest_framework import serializersfrom rest_framework.viewsets import ModelViewSetfrom django_filters.rest_framework import DjangoFilterBackendfrom app01 import modelsclass 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 666class 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 serializersfrom rest_framework.viewsets import ModelViewSetfrom django_filters.rest_framework import DjangoFilterBackend, OrderingFilterfrom django_filters import FilterSet, filtersfrom app01 import modelsclass 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 666class 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 serializersfrom rest_framework.viewsets import ModelViewSetfrom app01 import modelsfrom rest_framework.filters import OrderingFilterclass 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 666class 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 serializersfrom rest_framework.viewsets import ModelViewSetfrom app01 import modelsfrom rest_framework.filters import SearchFilterclass 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 666class 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 "\"

相关新闻