手摸手,带你用Django REST Framework撸接口系列九(过滤篇)
REST framework列表视图的默认行为是返回一个model的全部queryset。通常你却想要你的API来限制queryset返回的数据。这个时候就引入了我们的过滤器。
Django REST Framework系列文章
- 手摸手,带你用Django REST Framework撸接口系列一(基础篇)
- 手摸手,带你用Django REST Framework撸接口系列二(序列化器篇)
- 手摸手,带你用Django REST Framework撸接口系列三(视图篇)
- 手摸手,带你用Django REST Framework撸接口系列四(渲染器篇)
- 手摸手,带你用Django REST Framework撸接口系列五(路由篇)
- 手摸手,带你用Django REST Framework撸接口系列六(认证篇)
- 手摸手,带你用Django REST Framework撸接口系列七(权限篇)
- 手摸手,带你用Django REST Framework撸接口系列八(限流篇)
- 手摸手,带你用Django REST Framework撸接口系列九(过滤篇)
- 手摸手,带你用Django REST Framework撸接口系列十(排序篇)
- 手摸手,带你用Django REST Framework撸接口系列十一(分页篇)
- 手摸手,带你用Django REST Framework撸接口系列十二(异常处理篇)
- 手摸手,带你用Django REST Framework撸接口系列十三(自动生成接口文档篇)
项目需求
当你发送GET请求到/api/articles?page=3时可以得到下面返回的分页数据列表。现在我们希望对结果进行进一步过滤,比如返回标题含有关键词”华为”的文章资源列表。我们到底该怎么做呢? 本例中演示三种过滤方法, 你可以根据实际项目开发需求去使用。
重写get_queryset
最简单的过滤任意GenericAPIView
子视图queryset的方法就是重写它的.get_queryset()
方法。
重写这个方法允许你使用很多不同的方式来定制视图返回的queryset。
此方法不依赖于任何第三方包, 只适合于需要过滤的字段比较少的模型。比如这里我们希望对文章title进行过滤,我们只需要修改ArticleView视图函数类即可。
1 | class ArticleView(viewsets.ModelViewSet): |
修改好视图类后,发送GET请求到/api/articles/?q=华为, 你将得到所有标题含有华为关键词的文章列表,这里显示一共有3条结果。
注意:DRF中你通过request.query_params
获取GET请求发过来的参数,而不是request.GET。如果你希望获取从URL里传递的参数,你可以使用self.kwargs['param1']
。
假如你的URL配置如下所示:
1 | re_path('^articles/(?P<username>.+)/$', AricleView.as_view()), |
在视图中你可以通过self.kwargs['username']
获取URL传递过来的用户名。
1 | class ArticleView(generics.ListAPIView): |
当一个模型需要过滤的字段很多且不确定时(比如文章状态、正文等等), 重写get_queryset方法将变得非常麻烦,更好的方式是借助django-filter这个第三方库实现过滤。
使用django-filter
django-filter
库包含一个DjangoFilterBackend
类,该类支持REST框架的高度可定制的字段过滤。这也是小编推荐的过滤方法, 因为它自定义需要过滤的字段非常方便, 还可以对每个字段指定过滤方法(比如模糊查询和精确查询)。具体使用方式如下:
安装django-filter
1 | pip install django-filter |
把django_filters
添加到INSTALLED_APPS中去。
1 | INSTALLED_APPS = [ |
接下来你还需要把DjangoFilterBackend
设为过滤后台。你可以在settings.py
中进行全局配置。
1 | REST_FRAMEWORK = { |
还可以在单个视图中使用它。
1 | from django_filters.rest_framework import DjangoFilterBackend |
在类视图中使用django-filter时,你可以直接通过filter_fields
设置希望过滤的字段,如下所示:
1 | from django_filters.rest_framework import DjangoFilterBackend |
如果你希望进行更多定制化的行为,你需要自定义FilterSet类,然后指定filter_class
。
自定义FilterSet类
1 | import django_filters |
接下来通过filter_class
使用它。
1 | from api.filter.article import ArticleFilter |
你还可以看到REST框架提供了一个新的Filters下拉菜单按钮,包含我们自定义过滤器中设置的两个字段(标题和状态)的完全匹配和标题的包含匹配。可以帮助您对结果进行过滤(见上图标红部分)。
使用SearchFilter类
其实DRF自带了具有过滤功能的SearchFilter
类,其使用场景与Django-filter的单字段过滤略有不同,更侧重于使用一个关键词对模型的某个字段或多个字段同时进行搜索。
SearchFilter
类支持基于简单单查询参数的搜索,并且基于Django admin的搜索功能。
使用这个类,你还需要指定search_fields
, 具体使用方式如下:
1 | class ArticleView(viewsets.ModelViewSet): |
注意:这里进行搜索查询的默认参数名为?search=xxx。
SearchFilter类非常有用,因为它不仅支持对模型的多个字段进行查询,还支持ForeinKey和ManyToMany字段的关联查询。按如下修改search_fields
, 就可以同时搜索标题或用户名含有某个关键词的文章资源列表。修改好后,作者用户名里如果有django,该篇文章也会包含在搜索结果了。
1 | search_fields = ('title', 'author__username') |
默认情况下,SearchFilter类搜索将使用不区分大小写的部分匹配(icontains)。你可以在search_fields中添加各种字符来指定匹配方法。
- ’^’开始 - 搜索。
- ’=’完全匹配。
- ’@’全文搜索。
- ’$’正则表达式搜索。
例如:search_fields = (‘=title’, )精确匹配title。
自定义SearchFilter类
默认SearchFilter类仅支持?search=xxx
这个传递参数,你可以通过设置SEARCH_PARAM
覆盖。另外你还可以重写get_search_fileds
方法改变它的行为。下例中,当你按照?search=关键字&title_only=True提交请求时,它将只针对title进行查询。
1 | from rest_framework.filters import SearchFilter |
Django REST Framework系列文章
- 手摸手,带你用Django REST Framework撸接口系列一(基础篇)
- 手摸手,带你用Django REST Framework撸接口系列二(序列化器篇)
- 手摸手,带你用Django REST Framework撸接口系列三(视图篇)
- 手摸手,带你用Django REST Framework撸接口系列四(渲染器篇)
- 手摸手,带你用Django REST Framework撸接口系列五(路由篇)
- 手摸手,带你用Django REST Framework撸接口系列六(认证篇)
- 手摸手,带你用Django REST Framework撸接口系列七(权限篇)
- 手摸手,带你用Django REST Framework撸接口系列八(限流篇)
- 手摸手,带你用Django REST Framework撸接口系列九(过滤篇)
- 手摸手,带你用Django REST Framework撸接口系列十(排序篇)
- 手摸手,带你用Django REST Framework撸接口系列十一(分页篇)
- 手摸手,带你用Django REST Framework撸接口系列十二(异常处理篇)
- 手摸手,带你用Django REST Framework撸接口系列十三(自动生成接口文档篇)