You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django Rest Framework序列化器中对嵌套列表按指定字段排序

问题描述

前端收到的cou_charges_detail_row列表未按biller_category_ref_id升序排列,需要后端返回时将该列表按此字段升序排序。

当前返回数据示例:

{
  "id": 1,
  "tenant_id": 73,
  "product_channel": 2,
  "revision_status": "Effective",
  "cou_charges_detail_row": [
    {
      "biller_category_ref_id": 23,
      "rate_flag": false,
      "rate_percentage": "0.75",
      "min_value": 1,
      "max_value": 5000
    },
    {
      "biller_category_ref_id": 18,
      "rate_flag": false,
      "rate_percentage": "0.30",
      "min_value": 1,
      "max_value": 10000
    },
    // 剩余31条数据
  ]
}

预期返回格式:

{
  "id": 1,
  "tenant_id": 73,
  "product_channel": 2,
  "revision_status": "Effective",
  "cou_charges_detail_row": [
    {
      "biller_category_ref_id": 18,
      "rate_flag": false,
      "rate_percentage": "0.30",
      "min_value": 1,
      "max_value": 10000
    },
    {
      "biller_category_ref_id": 23,
      "rate_flag": false,
      "rate_percentage": "0.75",
      "min_value": 1,
      "max_value": 5000
    },
    // 剩余31条数据
  ]
}

相关代码片段如下:

views.py

class COUChargesViewSet(viewsets.ModelViewSet):
    queryset = CustomerOUCharges.objects.filter(is_deleted=False, is_active=True).order_by('-id')
    serializer_class = COUChargesSerializer

    def list(self, request):
        tenant_id = LoginSerializer.get(request.user).values_list("tenant_id", flat=True)
        if 'id' in self.request.GET:
            charges_obj = CustomerOUCharges.objects.filter(is_deleted=False,id = request.GET["id"]).exclude(revision_status='History').order_by('-id')
            serializer = self.get_serializer(charges_obj, many=True)
            return Response(serializer.data)
        else:
            charges_obj = CustomerOUCharges.objects.filter(tenant_id__in =tenant_id, is_deleted=False, is_active=True).exclude(revision_status='History').order_by('-id')
            serializer = COUChargesSerializer(charges_obj, many=True)
            return Response(serializer.data)

serializers.py

class COUChargesSerializer(serializers.ModelSerializer):
    tenant_name = serializers.CharField(source=varible_class.tenant_id_tenant_name, read_only=True)
    cou_charges_detail_row = COUChargesDetailsSerializer(many=True)

    class Meta:
        model = CustomerOUCharges
        fields = ('__all__')


class COUChargesDetailsSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(required=False)

    class Meta:
        model = CustomerOUChargesDetails
        fields = '__all__'
        list_serializer_class = FilterDeleteListSerializer

models.py

class CustomerOUCharges(models.Model):
    tenant_id = models.ForeignKey(Tenant, verbose_name="COU Tenant Id", on_delete=models.PROTECT,related_name='customerou_tenant_id')
    product_channel = models.ForeignKey(ProductChannelMst, verbose_name=product_channel, on_delete=models.PROTECT, related_name='customerou_charges_product_channel')
    revision_status = models.CharField(choices=REVISION_STATUS_CHOICES, max_length=20, verbose_name=revision_status)


class CustomerOUChargesDetails(models.Model):
    header_ref_id = models.ForeignKey(CustomerOUCharges, default=0, verbose_name=header_ref_id,on_delete=models.PROTECT, related_name='cou_charges_detail_row')
    biller_category_ref_id = models.ForeignKey(BillerCategory, verbose_name=biller_cat_id, on_delete=models.PROTECT, blank=True, null=True)
    rate_flag = models.BooleanField(default=False, verbose_name=rate_flag)
    rate_percentage = models.DecimalField(default=0, max_digits=10, decimal_places=2, verbose_name=rate_percentage, blank=True, null=True)
    min_value  = models.IntegerField(default=0, verbose_name=min_value)
    max_value  = models.IntegerField(default=0, verbose_name=max_value)

解决方案

方法一:模型层设置全局默认排序

修改CustomerOUChargesDetails模型,添加Meta类指定默认排序规则,所有获取该模型数据的操作都会自动按biller_category_ref_id升序排列:

# models.py
class CustomerOUChargesDetails(models.Model):
    header_ref_id = models.ForeignKey(CustomerOUCharges, default=0, verbose_name=header_ref_id,on_delete=models.PROTECT, related_name='cou_charges_detail_row')
    biller_category_ref_id = models.ForeignKey(BillerCategory, verbose_name=biller_cat_id, on_delete=models.PROTECT, blank=True, null=True)
    rate_flag = models.BooleanField(default=False, verbose_name=rate_flag)
    rate_percentage = models.DecimalField(default=0, max_digits=10, decimal_places=2, verbose_name=rate_percentage, blank=True, null=True)
    min_value  = models.IntegerField(default=0, verbose_name=min_value)
    max_value  = models.IntegerField(default=0, verbose_name=max_value)

    class Meta:
        ordering = ['biller_category_ref_id']

方法二:序列化器层动态排序

如果不想修改全局排序规则,可在COUChargesSerializer中自定义字段,手动对关联数据排序:

# serializers.py
class COUChargesSerializer(serializers.ModelSerializer):
    tenant_name = serializers.CharField(source=varible_class.tenant_id_tenant_name, read_only=True)
    
    def get_cou_charges_detail_row(self, obj):
        # 获取关联数据并按指定字段升序排序
        sorted_details = obj.cou_charges_detail_row.all().order_by('biller_category_ref_id')
        return COUChargesDetailsSerializer(sorted_details, many=True).data

    cou_charges_detail_row = serializers.SerializerMethodField()

    class Meta:
        model = CustomerOUCharges
        fields = ('__all__')

方法三:视图层预取排序(性能优化)

在视图查询集中使用Prefetch预取关联数据并指定排序,减少数据库查询次数的同时完成排序:

首先导入Prefetch:

from django.db.models import Prefetch

修改视图中的查询集:

# views.py
class COUChargesViewSet(viewsets.ModelViewSet):
    queryset = CustomerOUCharges.objects.filter(is_deleted=False, is_active=True).order_by('-id').prefetch_related(
        Prefetch('cou_charges_detail_row', queryset=CustomerOUChargesDetails.objects.order_by('biller_category_ref_id'))
    )
    serializer_class = COUChargesSerializer

    def list(self, request):
        tenant_id = LoginSerializer.get(request.user).values_list("tenant_id", flat=True)
        if 'id' in self.request.GET:
            charges_obj = CustomerOUCharges.objects.filter(is_deleted=False,id = request.GET["id"]).exclude(revision_status='History').order_by('-id').prefetch_related(
                Prefetch('cou_charges_detail_row', queryset=CustomerOUChargesDetails.objects.order_by('biller_category_ref_id'))
            )
            serializer = self.get_serializer(charges_obj, many=True)
            return Response(serializer.data)
        else:
            charges_obj = CustomerOUCharges.objects.filter(tenant_id__in =tenant_id, is_deleted=False, is_active=True).exclude(revision_status='History').order_by('-id').prefetch_related(
                Prefetch('cou_charges_detail_row', queryset=CustomerOUChargesDetails.objects.order_by('biller_category_ref_id'))
            )
            serializer = COUChargesSerializer(charges_obj, many=True)
            return Response(serializer.data)

内容的提问来源于stack exchange,提问作者Purushottam Nawale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 04:09:55