Skip to content

Latest commit

 

History

History
99 lines (66 loc) · 2.95 KB

100-过滤文章.md

File metadata and controls

99 lines (66 loc) · 2.95 KB

有些时候用户需要某个特定范围的文章(比如搜索功能),这时候后端需要把返回的数据进行过滤。

最简单的过滤方法就是修改视图集中的 queryset 属性了:

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.filter(author__username='Obama')
    ...

但是这样会导致原本正常的列表也都过滤了,太傻了。因此需要寻找更聪明的办法。

参数过滤

假设有如下带有参数的 GET 请求:

http://127.0.0.1:8000/api/article/?username=Obama

我们可以覆写 get_queryset() 方法来实现过滤:

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    ...
    
    def get_queryset(self):
        queryset = self.queryset
        username = self.request.query_params.get('username', None)

        if username is not None:
            queryset = queryset.filter(author__username=username)

        return queryset

这样就实现了过滤。但是如此常用的功能,必然已经有现成的轮子了。在博客项目中使用轮子可以更快更好的完成任务,所以接下来就来看看通用的过滤功能。

注意上面那个请求尾部的斜杠。虽然在浏览器中这个斜杠是可选的,但是在命令行中发送请求是必须要携带的(DRF 3.11.0)。

通用过滤

还记得刚安装 DRF 时顺便安装的 django-filter 吗,这就是用于过滤的轮子,现在派上用场了。

要将它作为默认的过滤引擎后端,写到配置文件中:

# drf_vue_blog/settings.py

...
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
    ...
}

你也可以将其单独配置在特定的视图中:

from django_filters.rest_framework import DjangoFilterBackend


class ArticleViewSet(viewsets.ModelViewSet):
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['author__username', 'title']

    ...

如果要实现单纯的完全匹配,上面这样写就可以了,请求参数可以单个字段也可以联合:

C:\...>http http://127.0.0.1:8000/api/article/?author__username=dusai&title=newtest

在 windows 系统用 httpie 时,上述请求中的 & 符号需要加上双引号,即变成 "&"。这是因为 & 符是系统的预留符号。实际在接口中的请求是不需要引号的。

如果要实现更常用的模糊匹配,就可以使用 SearchFilter 做搜索后端:

# article/views.py

...
from rest_framework import filters

class ArticleViewSet(viewsets.ModelViewSet):
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
    permission_classes = [IsAdminUserOrReadOnly]

    filter_backends = [filters.SearchFilter]
    search_fields = ['title']
    
    # 这个属性不需要了
    # filterset_fields = ['author__username', 'title']

非常轻松就实现了对文章标题的检索。