如何在 ListAPIView 中使用 django-filter 对过滤结果进行排序
Posted
技术标签:
【中文标题】如何在 ListAPIView 中使用 django-filter 对过滤结果进行排序【英文标题】:How to sort the results of filtering with django-filter in a ListAPIView 【发布时间】:2018-08-10 03:42:50 【问题描述】:我有一个 ListAPIView
,它使用 DjangoFilterBackend
根据 url 参数过滤房间。下面的代码可以很好地做到这一点。
现在,我想根据 Room 对象的其他属性、另一个 url 参数以及我们对发出请求的用户的了解,对结果进行排序。函数本身无关紧要。
应用已有的过滤器后,如何对结果进行排序?
如果我自己进行过滤,我想我可以在get_queryset
中进行过滤、计算分数并对结果进行排序,但我不知道在使用django-filter
进行过滤后如何执行此操作。
查询示例
例如,我将执行此查询以按价格低于 100 进行过滤。other_field
值将用于计算排序分数:
http://localhost:8000/api/search/rooms?price=100&other_field=200
代码
class RoomFilter(filters.FilterSet):
price = filters.NumberFilter(name="price", lookup_expr='lte')
features = filters.ModelMultipleChoiceFilter(
name="features",
conjoined=True,
queryset=Features.objects.all()
)
class Meta:
model = Room
fields = ['price', 'features']
class RoomSearchView(generics.ListAPIView):
queryset = Room.objects.all()
serializer_class = RoomSearchSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = RoomFilter
【问题讨论】:
【参考方案1】:尝试在您的 API 中覆盖 list()
,如下所示,
class RoomSearchView(generics.ListAPIView):
queryset = Room.objects.all()
serializer_class = RoomSearchSerializer
filter_backends = (filters.DjangoFilterBackend,)
filter_class = RoomFilter
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
queryset = queryset.order_by('-id') # change is here >> sorted with reverse order of 'id'
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
【讨论】:
太棒了,它完全符合我的需要!然后我可以在那里进行任何类型的排序,包括添加一个额外的分数列。谢谢!【参考方案2】:您可以使用 FilterSet 类(在您的情况下为 RoomFilter)以更灵活的方式做到这一点
在 RoomFilter 类中使用 fileds 关键字参数定义一个 OrderFilter
fields是model field name: parameter name的映射。
(https://django-filter.readthedocs.io/en/stable/ref/filters.html)
所以你可以这样做:
class RoomFilter(filters.FilterSet):
price = filters.NumberFilter(name="price", lookup_expr='lte')
features = filters.ModelMultipleChoiceFilter(
name="features",
conjoined=True,
queryset=Features.objects.all()
)
o = OrderingFilter(
fields=(
('id', 'id'),
('price', 'price'),
# and any model field you want to sort based on
)
)
class Meta:
model = Room
fields = ['price', 'features']
根据id和升序排序:
http://localhost:8000/api/search/rooms?price=100&other_field=200&o=id
根据id和降序排序:
http://localhost:8000/api/search/rooms?price=100&other_field=200&o=-id
【讨论】:
以上是关于如何在 ListAPIView 中使用 django-filter 对过滤结果进行排序的主要内容,如果未能解决你的问题,请参考以下文章
如何将两个不同的ListAPIView转换为单个ModelViewSet
django drf GenericAPIView和ListAPIView
(生鲜项目)08. ModelSerializer 实现商品列表页, 使用Mixin来实现返回, 以及更加方便的ListAPIView, 以及分页的设置