如果某个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. 内置filterdrf源码中内置了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 "\"