Django Rest Framework排序功能失效,疑似与get_queryset有关如何解决?
DRF排序功能失效问题解决方案
根因分析
- 你重写了
ListAPIView的list方法,跳过了DRF默认的过滤器执行逻辑:原生list方法会调用self.filter_queryset()对查询集做过滤、排序处理,你直接取get_queryset()返回的原始查询集,完全没有走OrderingFilter的排序流程,导致排序不生效。 - 你在
ordering_fields中添加了cpc、cpm两个序列化后动态计算的非数据库字段,排序过滤器是作用在数据库查询阶段的,数据库中不存在这两个字段,按这两个字段排序也会失效。
修复步骤
- 先修复基础排序逻辑:在
list方法中先调用filter_queryset处理查询集,把原有list方法的第一行修改为:
queryset = self.filter_queryset(self.get_queryset())
修改后即可支持date、views、clicks、cost这几个数据库原生字段的排序功能。
- 如果需要支持
cpc、cpm字段的排序,建议把计算逻辑移到数据库查询层,通过annotate生成计算字段,修改后的完整视图代码如下:
from django.db.models import F, ExpressionWrapper, FloatField class ShowStats(ListAPIView): serializer_class = StatsSerializer filter_backends = (DjangoFilterBackend, filters.OrderingFilter) ordering_fields = ('date', 'views', 'clicks', 'cost', 'cpc', 'cpm') ordering = ('views',) def get_queryset(self): return Stats.objects.filter( date__range=[self.kwargs['from'], self.kwargs['to']] ).annotate( cpc=ExpressionWrapper(F('cost')/F('clicks'), output_field=FloatField()), cpm=ExpressionWrapper(F('cost')/F('views')*1000, output_field=FloatField()) ) def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) serializer = self.get_serializer(queryset, many=True) return Response(data=serializer.data)
该方案直接在数据库层面完成字段计算和排序,性能远高于序列化后在Python层做排序,适合各类数据量场景。
内容的提问来源于stack exchange,提问作者gornichnyx
相关产品推荐
相关产品推荐

