基于Django REST + Vue实现自定义排序功能的技术咨询
Django REST后端适配Vue前端排序功能实现方案
需求说明
前端通过sort_key(排序字段)和sort_type(排序类型:ascending/descending)传递排序参数,示例请求:
GET /api/v1/stocks/?sort_key=FBS&sort_type=ascending GET /api/v1/stocks/?sort_key=FBS&sort_type=descending
现有代码问题分析
Stock模型的Meta.ordering配置了"-present_fbs",但模型中不存在该字段,需改为"-fbs"避免报错。StocksApi的get_queryset固定了order_by("-fbs"),会忽略前端传递的排序参数,无法实现动态排序。
实现方案建议
方案一:自定义OrderingFilter(推荐,符合DRF规范)
通过继承DRF的OrderingFilter,适配前端传递的参数格式,同时实现字段映射与参数校验:
# views.py from rest_framework.filters import OrderingFilter from rest_framework.viewsets import GenericViewSet, ListModelMixin from .models import Stock from .serializers import StocksSerializer from rest_framework.permissions import IsAuthenticated class CustomSortFilter(OrderingFilter): def get_ordering(self, request, queryset, view): sort_key = request.query_params.get('sort_key') sort_type = request.query_params.get('sort_type') # 前端字段名 -> 模型字段名映射,可扩展其他字段 field_mapping = { 'FBS': 'fbs', } # 参数校验与排序逻辑 if sort_key and sort_type: model_field = field_mapping.get(sort_key) if model_field and sort_type in ('ascending', 'descending'): return [f'-{model_field}'] if sort_type == 'descending' else [model_field] # 无合法参数时返回默认排序 return ['-fbs'] class StocksApi(ListModelMixin, GenericViewSet): serializer_class = StocksSerializer permission_classes = (IsAuthenticated,) pagination_class = StocksDefaultPagination filter_backends = [CustomSortFilter] # 可选:明确允许排序的字段,增强安全性 ordering_fields = ['fbs'] def get_queryset(self): return Stock.objects.filter(store__user_id=self.request.user.pk)
# models.py class Stock(models.Model): class Meta: verbose_name_plural = "Stocks" verbose_name = "Stock" ordering = ("-fbs",) # 修正字段名,作为全局默认排序 store = models.ForeignKey(Store, on_delete=models.CASCADE, null=True, verbose_name="Store") fbs = models.PositiveIntegerField(default=0, verbose_name="FBS")
方案二:手动在get_queryset中处理参数(简单场景适用)
直接在get_queryset方法中读取前端参数,动态调整查询集的排序:
# views.py class StocksApi(ListModelMixin, GenericViewSet): serializer_class = StocksSerializer permission_classes = (IsAuthenticated,) pagination_class = StocksDefaultPagination def get_queryset(self): queryset = Stock.objects.filter(store__user_id=self.request.user.pk) sort_key = self.request.query_params.get('sort_key') sort_type = self.request.query_params.get('sort_type') field_mapping = { 'FBS': 'fbs', } if sort_key and sort_type in ('ascending', 'descending'): model_field = field_mapping.get(sort_key) if model_field: order_str = f'-{model_field}' if sort_type == 'descending' else model_field return queryset.order_by(order_str) # 无合法参数时返回默认排序 return queryset.order_by('-fbs')
关键注意事项
- 字段映射:必须通过映射关系将前端字段名转换为模型字段名,避免直接使用用户输入的参数,防止非法字段排序或潜在安全问题。
- 参数校验:需校验
sort_type只能是ascending或descending,避免无效参数导致排序异常。 - 默认排序:确保在未传递排序参数时,查询集有合理的默认排序逻辑,保持接口行为一致性。
内容的提问来源于stack exchange,提问作者Iren E
相关产品推荐
相关产品推荐

