如何用Django Rest Framework序列化器构造目标JSON响应?
解决方案:通过DRF序列化器实现分组及ChartJS适配格式
当然可以用Django Rest Framework(DRF)的序列化器实现你需要的两种数据格式!我会分两步帮你搞定:先实现按meternumber拆分的分组响应,再直接生成Angular ChartJS所需的格式。
一、实现按meternumber分组的响应格式
要得到包含servicenumber、meternumber和嵌套usagedata的结构,我们需要用到嵌套序列化器,同时在视图层先对数据进行分组处理。
1. 定义嵌套序列化器
首先,保留你已有的MeterUsageSerializer,再新增一个用于分组的序列化器:
from rest_framework import serializers from .models import MeterUsage # 你原有的基础序列化器 class MeterUsageSerializer(serializers.ModelSerializer): class Meta: model = MeterUsage fields = ('usagedatetime', 'usage') # 新增分组序列化器 class MeterGroupSerializer(serializers.Serializer): servicenumber = serializers.IntegerField() meternumber = serializers.IntegerField() usagedata = MeterUsageSerializer(many=True) # 嵌套使用基础序列化器
2. 在视图中分组并序列化数据
为了减少数据库查询次数,我们可以一次性获取所有数据,再通过itertools.groupby在内存中分组(比多次查询更高效):
from rest_framework.views import APIView from rest_framework.response import Response from itertools import groupby from operator import attrgetter from .models import MeterUsage from .serializers import MeterGroupSerializer class GroupedMeterDataView(APIView): def get(self, request): # 获取所有记录,并按servicenumber、meternumber、usagedatetime排序(groupby依赖有序数据) all_records = MeterUsage.objects.all().order_by( 'servicenumber', 'meternumber', 'usagedatetime' ) grouped_data = [] # 按(servicenumber, meternumber)组合分组 grouping_key = attrgetter('servicenumber', 'meternumber') for (serv_num, meter_num), records_group in groupby(all_records, key=grouping_key): # 将分组后的记录序列化为usagedata usage_data = MeterUsageSerializer(list(records_group), many=True).data grouped_data.append({ 'servicenumber': serv_num, 'meternumber': meter_num, 'usagedata': usage_data }) # 用分组序列化器处理最终数据 serializer = MeterGroupSerializer(grouped_data, many=True) return Response(serializer.data)
这样返回的响应就完全符合你需要的分组格式了。
二、直接生成ChartJS所需的格式
如果你的前端只需要ChartJS的label-data结构,可以直接在后端构造对应格式,无需先返回分组数据再前端处理。
1. 定义ChartJS专用序列化器
class MeterChartDataSerializer(serializers.Serializer): label = serializers.CharField() # 将meternumber转为字符串作为标签 data = serializers.ListField(child=serializers.DecimalField(max_digits=38, decimal_places=8))
2. 在视图中构造ChartJS数据
class MeterChartDataView(APIView): def get(self, request): all_records = MeterUsage.objects.all().order_by( 'servicenumber', 'meternumber', 'usagedatetime' ) chart_data = [] grouping_key = attrgetter('servicenumber', 'meternumber') for (serv_num, meter_num), records_group in groupby(all_records, key=grouping_key): # 提取按时间排序的usage值列表 usage_values = [record.usage for record in records_group] chart_data.append({ 'label': str(meter_num), 'data': usage_values }) serializer = MeterChartDataSerializer(chart_data, many=True) return Response(serializer.data)
这个接口返回的格式和你需要的chartData完全一致,前端可以直接拿来给ChartJS用。
为什么之前的尝试可能无效?
你之前的问题大概率是没有在视图层先对数据进行分组,而是直接序列化了所有MeterUsage对象,导致返回的是扁平的列表。DRF的序列化器本身不会自动帮你分组,需要你先构造好分组后的数据集,再用序列化器处理结构。
内容的提问来源于stack exchange,提问作者ianbroad
相关产品推荐
相关产品推荐

