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

如何在Django REST Framework中正确序列化数据,实现按Ticker聚合返回

问题描述

我是Django REST Framework的新手,当前接口返回的数据格式不符合需求,需要将返回数据按Ticker分组,把对应daily_pe聚合为数组。

现有代码

models.py

class Price(models.Model):
    ticker = models.CharField(max_length=15, null=False, blank=False) 
    price_date=models.DateField(null=False, blank=False)
    daily_pe = models.FloatField(blank=True, null=True)
    
    class Meta:
        db_table= 'price'
        unique_together = ('ticker', 'price_date')

    def __str__(self):
        return "%s %s %s " % (self.ticker, self.price_date, self.daily_pe)

serializers.py

class ChartSerilizer(serializers.ModelSerializer):
    class Meta:
        model = Price
        fields = ['ticker', 'daily_pe']

views.py

class peChartViewSet(APIView):
    def get(self, request):
        queryset = Price.objects.all()
        serializer = ChartSerilizer(queryset, many=True)
        return JsonResponse(serializer.data, safe=False)

当前返回格式

[
    {
        "ticker": "AAPL",
        "daily_pe": 25.144920802584345
    },
    {
        "ticker": "AAPL",
        "daily_pe": 25.043920960028977
    },
    {
        "ticker": "WMT",
        "daily_pe": 24.930801136366966
    },
    {
        "ticker": "WMT",
        "daily_pe": 25.504480242081453
    },
]

期望返回格式

[
    {
         "Ticker": "AAPL",
         "daily_pe": [25.144920802584345, 25.043920960028977]
    },
    {
         "Ticker": "WMT",
         "daily_pe": [24.930801136366966,25.504480242081453]
    }
]

解决方案

方法一:数据库层面聚合(推荐)

利用Django的聚合函数直接在查询阶段完成分组和聚合,效率更高。如果使用PostgreSQL,可直接用ArrayAgg:

修改views.py

from django.contrib.postgres.aggregates import ArrayAgg
from rest_framework.response import Response

class peChartViewSet(APIView):
    def get(self, request):
        # 按ticker分组,聚合daily_pe为数组
        queryset = Price.objects.values('ticker').annotate(
            daily_pe=ArrayAgg('daily_pe')
        ).order_by('ticker')
        
        # 转换键名并整理格式
        result = [{"Ticker": item['ticker'], "daily_pe": item['daily_pe']} for item in queryset]
        return Response(result)

注:若使用MySQL,可替换为GroupConcat,之后再将字符串分割为数组,示例:

from django.db.models import Func, Value
class GroupConcat(Func):
    function = 'GROUP_CONCAT'
    template = "%(function)s(%(expressions)s SEPARATOR ',')"

# 查询时
queryset = Price.objects.values('ticker').annotate(
    daily_pe_str=GroupConcat('daily_pe')
).order_by('ticker')
result = [
    {"Ticker": item['ticker'], "daily_pe": list(map(float, item['daily_pe_str'].split(',')))} 
    for item in queryset
]

方法二:Python层面分组处理

如果不想依赖数据库特定函数,可先获取全量数据,再在代码中完成分组:

修改views.py

from collections import defaultdict
from rest_framework.response import Response

class peChartViewSet(APIView):
    def get(self, request):
        queryset = Price.objects.all()
        serializer = ChartSerilizer(queryset, many=True)
        
        # 按ticker分组聚合daily_pe
        grouped_data = defaultdict(list)
        for item in serializer.data:
            grouped_data[item['ticker']].append(item['daily_pe'])
        
        # 转换为期望格式
        result = [{"Ticker": ticker, "daily_pe": pes} for ticker, pes in grouped_data.items()]
        return Response(result)

可选:自定义序列化器规范输出

若需要更严谨的字段校验和序列化流程,可新增自定义序列化器:

新增serializers.py内容

class GroupedChartSerializer(serializers.Serializer):
    Ticker = serializers.CharField()
    daily_pe = serializers.ListField(child=serializers.FloatField())

配合方法二修改views.py

class peChartViewSet(APIView):
    def get(self, request):
        queryset = Price.objects.all()
        serializer = ChartSerilizer(queryset, many=True)
        
        grouped_data = defaultdict(list)
        for item in serializer.data:
            grouped_data[item['ticker']].append(item['daily_pe'])
        
        result = [{"Ticker": ticker, "daily_pe": pes} for ticker, pes in grouped_data.items()]
        # 使用自定义序列化器处理输出
        grouped_serializer = GroupedChartSerializer(result, many=True)
        return Response(grouped_serializer.data)

内容的提问来源于stack exchange,提问作者shyam yadav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:06:44