如何在Django中按非模型字段post_count对分类进行排序
解决方案
方法一:注解字段+原生OrderingFilter直接实现
核心思路是给Category查询集通过annotate添加post_count计算字段,让OrderingFilter能识别这个虚拟字段进行排序。
修改视图代码如下:
from django.db.models import Count from rest_framework.filters import OrderingFilter from rest_framework.generics import GenericAPIView, ListModelMixin from category.models import Category from category.serializers import CategorySerializer class CategoryView(GenericAPIView, ListModelMixin): # 用annotate给每个分类计算关联的文章数量,'post'是Post模型中关联Category的反向关联名,需根据实际模型调整 queryset = Category.objects.annotate(post_count=Count('post')) serializer_class = CategorySerializer filter_backends = [OrderingFilter] ordering_fields = ['post_count', 'name'] # 可添加其他需要排序的字段 authentication_classes = [] def get(self, request, *args, **kwargs): return self.list(request)
注意:如果Post模型中关联Category的外键设置了related_name(比如related_name="posts"),要把Count('post')改成Count('posts')。设置完成后,直接通过http://localhost:8000/api/category?ordering=-post_count即可实现按文章数量降序排序,逻辑和你给出的SQL完全一致。
方法二:自定义排序过滤器(按需选择)
如果希望只有当请求包含post_count排序参数时才执行计数计算(避免不必要的数据库开销),可以自定义过滤器:
from django.db.models import Count from rest_framework.filters import OrderingFilter class CustomOrderingFilter(OrderingFilter): def filter_queryset(self, request, queryset, view): ordering = self.get_ordering(request, queryset, view) if ordering and any('post_count' in item for item in ordering): # 仅当需要按post_count排序时,才添加注解 queryset = queryset.annotate(post_count=Count('post')) return super().filter_queryset(request, queryset, view) # 视图中替换为自定义过滤器 class CategoryView(GenericAPIView, ListModelMixin): queryset = Category.objects.all() serializer_class = CategorySerializer filter_backends = [CustomOrderingFilter] ordering_fields = ['post_count'] authentication_classes = [] def get(self, request, *args, **kwargs): return self.list(request)
可选:序列化器返回post_count字段
如果需要接口返回结果包含文章数量,修改序列化器:
from rest_framework import serializers from category.models import Category class CategorySerializer(serializers.ModelSerializer): post_count = serializers.IntegerField(read_only=True) class Meta: model = Category fields = ['id', 'name', 'post_count'] # 根据实际业务调整字段列表
内容的提问来源于stack exchange,提问作者Antoliny Lee
相关产品推荐
相关产品推荐

