手摸手,带你用Django REST Framework撸接口系列十(排序篇)

排序这篇文章其实应该是要挂在过滤篇的,因为对某个字段进行排序其实也是一种过滤的方式,只是过滤出来的还是返回一个model的全部queryset,在使用上也和过滤器没什么区别,我们就接着上篇过滤器来讲。

使用OrderingFilter类首先要把它加入到filter_backends, 然后指定排序字段即可。默认情况下,查询参数名为'ordering',但这可以通过settings配置restframe中使用ORDERING_PARAM设置覆盖。

1
2
3
4
5
6
7
8
9
10
11
from rest_framework.filters import  OrderingFilter


class ArticleView(viewsets.ModelViewSet):
"""文章列表视图类"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# 只允许登录用户访问
# permission_classes = (IsAuthenticated, )
pagination_class = MyPageNumberPagination
filter_backends = (OrderingFilter, )

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

点击DRF界面上的Filters按钮,你还会看到搜索和排序的选项,如果你不指定允许排序的字段的话,默认支持所有字段排序。

指定支持排序的字段

建议你明确指定API应在ordering filter中允许哪些字段。您可以通过在view中设置ordering_fields属性来实现这一点,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from rest_framework.filters import  OrderingFilter


class ArticleView(viewsets.ModelViewSet):
"""文章列表视图类"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# 只允许登录用户访问
# permission_classes = (IsAuthenticated, )
pagination_class = MyPageNumberPagination
# 排序过滤器
filter_backends = (OrderingFilter, )
# 允许的排序字段
ordering_fields = ('id', 'created_time')

这有助于防止意外的数据泄漏,例如允许用户针对密码哈希字段或其他敏感数据进行排序。

如果不在视图上指定ordering_fields属性,过滤器类将默认允许用户对serializer_class属性指定的serializer上的任何可读字段进行过滤。

如果你确信视图正在使用的queryset不包含任何敏感数据,则还可以通过使用特殊值'__all__'来明确指定view应允许对任何model字段或queryset进行排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from rest_framework.filters import  OrderingFilter


class ArticleView(viewsets.ModelViewSet):
"""文章列表视图类"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# 只允许登录用户访问
# permission_classes = (IsAuthenticated, )
pagination_class = MyPageNumberPagination
# 排序过滤器
filter_backends = (OrderingFilter, )
# 允许所有字段排序
ordering_fields = '__all__'

指定默认排序

如果在view中设置了ordering属性,则将把它用作默认排序。

通常,你可以通过在初始queryset上设置order_by来控制此操作,但是使用view中的ordering参数允许你以某种方式指定排序,然后可以将其作为上下文自动传递到呈现的模板。如果它们用于排序结果的话就能使自动渲染不同的列标题成为可能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from rest_framework.filters import  OrderingFilter


class ArticleView(viewsets.ModelViewSet):
"""文章列表视图类"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
# 只允许登录用户访问
# permission_classes = (IsAuthenticated, )
pagination_class = MyPageNumberPagination
# 排序过滤器
filter_backends = (OrderingFilter, )
# 允许的排序字段
ordering_fields = ('id', 'created_time')
# 默认排序字段
ordering = ('-created_time')

ordering属性可以是字符串或字符串的列表/元组。

小结

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