社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Django

如何在 Django REST Framework 中对分页结果过滤和排序?

CSDN • 4 年前 • 695 次点击  

作者 | 大江狗  责编 | 张文
来源 | Python Web 与 Django 开发
(ID:Python_Web_Django)

在本篇文章中我们将向你演示如何在 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 框架的高度可定制的字段过滤。自定义需要过滤的字段非常方便, 还可以对每个字段指定过滤方法(比如模糊查询和精确查询)。具体使用方式如下:

2.1 安装 django-filter

pip install django-filter

2.2  把 django_filters 添加到 INSTALLED_APPS

INSTALLED_APPS = [    ...,    django_filters,]

2.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')

2.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,没有相互冲突。




    



    



    



    

告别 Windows、Android,国产操作系统合力破局

那些追源码的平凡之路

Windows 游戏之父 Eric Engstrom 意外去世,享年55岁

 M1  RISC-V  ARM

 Cookie

VueReact 




    

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/105929
 
695 次点击