用DRF做了一些接口,用到数据的过滤,每次许多fiter就挺烦人的,就琢磨了一个自定义的过滤类,交流一下,要是有高手看到就指点指点,还能怎么继续优化。
一般复杂查询,我习惯post提交,django有一个很好的django-filter库,就是自己使用的不是很习惯,而且django-filter是地址栏提交的,前端也不熟,调试不方便。
在rest_framework的filter已经提供了一个基类BaseFilterBackend,定义了filter_queryset的方法,所以继承BaseFilterBackend后重写这个方法就可以。
在ViewSet里面,我先预定义一个post_fields字典用于提交字段和搜索字段的转换:
class MyViewSets(MyModelViewSets):
filter_backends = [SearchFilterBackend]
my_post_fields = {'name': 'name', 'age':'age__range', 'type':'type__name'}
# 可以直接用 “__” 关联外键。如果需要扩大搜索范围,直接修改my_post_fields的内容就可以。
# 由于是字典定义,前后端提交字段名称完全可以和后端脱离。
过滤器类,主要使用Q对象来实现过滤,Q的默认关系OR,需要指定为AND,Q的条件只要在children的属性append进来就可以。
from rest_framework import filters
from django.db.models import Q
class SearchFilterBackend(filters.BaseFilterBackend):
def get_search_fields(self, view, request):
# 获取自定义的搜索列表
return getattr(view, 'my_post_fields', None)
def filter_queryset(self, request, queryset, view):
# 所有关键字是and关系,提交的字段不在预设范围的忽略,
# 提交一个值就判断一样,提交list类型,就是判断包含其中。
q_and = Q()
q_and.connector = 'AND'
for post_field, model_field in search_fields.items():
if post_field in data and data[post_field] is not None and data[post_field] not in [[], '']:
if type(data[post_field]) == list and not model_field.endswith('__range'):
search_type = '__in'
else:
search_type = ''
q_and.children.append((model_field + search_type, data[post_field]))
queryset = queryset.filter(q_and)
return queryset
自己用下来还觉得挺方便的,欢迎交流
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...





