Django REST Framework教程(9): 过滤(filter)与排序(多图)

Django REST Framework教程(9): 过滤(filter)与排序(多图)

 

在前面的DRF系列教程中,我们以博客为例介绍了序列化器(Serializer), 并使用基于类的视图APIView和ModelViewSet开发了针对文章资源进行增删查改的完整API端点,并详细对权限、认证(含jwt认证)和分页进行了总结与演示。在本篇文章中我们将向你演示如何在Django REST Framework中对分页结果进行进一步过滤和排序。

 

 

 前面教程中当你发送GET请求到/v1/articles?page=2时可以得到下面返回的分页数据列表。现在我们希望对结果进行进一步过滤,比如返回标题含有关键词django的文章资源列表。我们到底该怎么做呢? 本例中小编我将演示三种方法, 你可以根据实际项目开发需求去使用。

 

 

 

方法一:重写GenericsAPIView或viewset的get_queryset方法

此方法不依赖于任何第三方包, 只适合于需要过滤的字段比较少的模型。比如这里我们需要对文章title进行过滤,我们只需要修改ArticleList视图函数类即可。


# blog/views.py
from rest_framework import genericsfrom rest_framework import permissionsfrom .permissions import IsOwnerOrReadOnlyfrom .pagination import MyPageNumberPagination
class ArticleList(generics.ListCreateAPIView): serializer_class = ArticleSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly,) pagination_class = MyPageNumberPagination
def get_queryset(self): keyword = self.request.query_params.get('q') if not keyword: queryset = Article.objects.all() else: queryset = Article.objects.filter(title__icontains=keyword) return queryset
    # associate user with article author. def perform_create(self, serializer): serializer.save(author=self.request.user)

修改好视图类后,发送GET请求到/v1/articles?page=2&q=django, 你将得到所有标题含有django关键词的文章列表,这里显示一共有3条结果。

 

 

 

当一个模型需要过滤的字段很多且不确定时(比如文章状态、正文等等), 重写get_queryset方法将变得非常麻烦,更好的方式是借助django-filter这个第三方库实现过滤。

 

方法二:使用django-filter

django-filter库包含一个DjangoFilterBackend类,该类支持REST框架的高度可定制的字段过滤。这也是小编推荐的过滤方法, 因为它自定义需要过滤的字段非常方便, 还可以对每个字段指定过滤方法(比如模糊查询和精确查询)。具体使用方式如下:

 

1. 安装django-filter

pip install django-filter

2. 把django_filters添加到INSTALLED_APPS

INSTALLED_APPS = [    ...,    django_filters,]

3. 自定义FilterSet类。这里我们自定义了按标题关键词和文章状态进行过滤。

# blog/filters.py(新建)


import django_filtersfrom .models import Article
class ArticleFilter(django_filters.FilterSet): q = django_filters.CharFilter(field_name='title', lookup_expr='icontains')
class Meta: model = Article fields = ('title', 'status')

如果你对django-filter中自定义FilterSet类比较陌生的话,可以先阅读下面两篇文章:

4. 将自定义FilterSet类加入到View类或ViewSet,另外还需要将DjangoFilterBackend设为过滤后台,如下所示:

# New for django-filterfrom django_filters import rest_frameworkfrom .filters import ArticleFilter
class ArticleList(generics.ListCreateAPIView): queryset = Article.objects.all() serializer_class = ArticleSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly,) pagination_class = MyPageNumberPagination
    # new: filter backends and classes filter_backends = (rest_framework.DjangoFilterBackend,) filter_class = ArticleFilter
# associate request.user with author. def perform_create(self, serializer): serializer.save(author=self.request.user)

发送GET请求到/v1/articles?page=2&q=django&status=p, 你将得到如下返回结果,只包含发表了的文章。

 

 

你还可以看到REST框架提供了一个新的Filters下拉菜单按钮,可以帮助您对结果进行过滤(见上图标红部分)。

 

方法三:使用DRF提供的SearchFilter类

其实DRF自带了具有过滤功能的SearchFilter类,其使用场景与Django-filter的单字段过滤略有不同,更侧重于使用一个关键词对模型的某个字段或多个字段同时进行搜索。

 

使用这个类,你还需要指定search_fields, 具体使用方式如下:

from rest_framework import filters
class ArticleList(generics.ListCreateAPIView): queryset = Article.objects.all() serializer_class = ArticleSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly,) pagination_class = MyPageNumberPagination
    # new: add SearchFilter and search_fields filter_backends = (filters.SearchFilter, )    search_fields = ('title',)
# associate request.user with author. def perform_create(self, serializer): serializer.save(author=self.request.user)

发送GET请求到/v1/articles?page=1&search=django, 你将得到如下结果。注意:这里进行搜索查询的默认参数名为?search=xxx。

 

 

 

SearchFilter类非常有用,因为它不仅支持对模型的多个字段进行查询,还支持ForeinKey和ManyToMany字段的关联查询。按如下修改search_fields, 就可以同时搜索标题或用户名含有某个关键词的文章资源列表。修改好后,作者用户名里如果有django,该篇文章也会包含在搜索结果了。

search_fields = ('title', 'author__username')

默认情况下,SearchFilter类搜索将使用不区分大小写的部分匹配(icontains)。你可以在search_fields中添加各种字符来指定匹配方法。

  • '^'开始 - 搜索。

  • '='完全匹配。

  • '@'全文搜索。

  • '$'正则表达式搜索。

例如:search_fields = ('=title', )精确匹配title。

 

前面我们详细介绍了对结果进行过滤的3种方法,接下来我们再看看如何对结果进行排序,这里主要通过DRF自带的OrderingFilter类实现。

 

使用DRF的OrderingFilter类

使用OrderingFilter类首先要把它加入到filter_backends, 然后指定排序字段即可,如下所示:


from rest_framework import filters
class ArticleList(generics.ListCreateAPIView): queryset = Article.objects.all() serializer_class = ArticleSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly,) pagination_class = MyPageNumberPagination

filter_backends = (filters.SearchFilter, filters.OrderingFilter,) search_fields = ('title',) ordering_fields = ('create_date')

发送请求时只需要在参数上加上?ordering=create_date或者?ordering=-create_date即可实现对结果按文章创建时间正序和逆序进行排序。

 

点击DRF界面上的Filters按钮,你还会看到搜索和排序的选项

 

 

:实际开发应用中OrderingFilter类,SearchFilter类和DjangoFilterBackend经常一起联用作为DRF的filter_backends,没有相互冲突。

 

小结

本文详细总结了Django REST Framework中如何对返回的响应数据进行过滤和排序,你都学到了吗? 下面我们将开始介绍Django REST Framework的限流和自定义响应数据格式,欢迎关注我们的微信公众号【Python Web与Django开发】, 获取一手原创干货。

 

posted @ 2021-09-09 17:31  7411  阅读(615)  评论(0)    收藏  举报