文章目录
- 条件搜索
- 自定义Filter
- 第三方Filter
- 内置Filter
条件搜索
如果某个API需要传递一些条件进行搜索,其实就在是URL后面通过GET传参即可,例如:
/api/users?age=19&category=12
在drf中也有相应组件可以支持条件搜索。
自定义Filter
自定义filter后,需要在view视图类中定义filter_backeds
类变量,django会自动读取循环filter_backeds
中的filter类并执行实例化对象的filter_query
方法。(get,put,delete,patch都会执行,post不会)
# urls.py
from django.urls import path
from app01 import views
urlpatterns = [
path('api/users/', views.UserView.as_view(
{"get": "list", "post": "create"}
)),
path('api/users/<int:pk>/', views.UserView.as_view(
{"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}
)),
]
# views.py
from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from rest_framework.filters import BaseFilterBackend
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 Filter1(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
age = request.query_params.get('age')
if not age:
return queryset
return queryset.filter(age=age)
class Filter2(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
user_id = request.query_params.get('id')
if not user_id:
return queryset
return queryset.filter(id__gt=user_id)
class UserView(ModelViewSet):
filter_backends = [Filter1, Filter2]
queryset = models.UserInfo.objects.all()
serializer_class = UserModelSerializer
def perform_create(self, serializer):
""" 序列化:对请求的数据校验成功后,执行保存。"""
serializer.save(depart_id=1, password="123")
第三方Filter
在drf开发中有一个常用的第三方过滤器:DjangoFilterBackend。
pip install django-filter
注册app:
INSTALLED_APPS = [
...
'django_filters',
...
]
视图配置和应用(示例1):
最简单应用:
可以通过下载,django-filter组件,引入django_filter.rest_framework import DjangoFilterBancked。
在view视图类中定义filter_banckeds=[DjangoFilterBancked],和filterset_fields=[“id”,“name”,“age”]。
# 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):
还可以通过定义类变量
filterset_class
来定义更复杂的查询变量条件,flilter类应该继承
FilterSet
,(类的构建类似于MoldeForm)
from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from django_filters.rest_framework import DjangoFilterBackend
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):
depart = filters.CharFilter(field_name="depart__title", lookup_expr="exact")
min_id = filters.NumberFilter(field_name='id', lookup_expr='gte')
class Meta:
model = models.UserInfo
fields = ["min_id", "depart"]
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")
视图配置和应用(示例3):
构建filter类的字段:
NumberFilter,CharFilter,BooleanFilter,MultipleChoiceFilter,BaseInFilter,NumericRangeFilter,OrderingFilter,
还可以通过CharFilter使用自定义搜索的方法。
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'),
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',]
}
内置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): # ?search=DP%T 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 %DPT% ESCAPE '\' OR "app01_userinfo"."username" LIKE %DPT% ESCAPE '\' OR "app01_userinfo"."age" LIKE %DPT% ESCAPE '\'
若有错误与不足请指出,关注DPT一起进步吧!!!