Python DRF如何通过序列化器生成指定结构的JSON响应
DRF自定义JSON响应格式解决方案
问题根源
- 现有
RatingsSerializer将不同机构的评级作为同一条记录的两个字段返回,不符合目标格式中「每个机构作为ratings数组独立元素」的要求 - 字段名未做对应映射:
source需映射为review_org、report_url需映射为review_url - 空值返回字符串
'null',不符合预期的空数组格式 - 序列化方法中存在大量无意义的全表查询,性能损耗极大
修改后的序列化器代码
class CurriculumSerializer(ModelSerializer): grade_level = serializers.CharField(source='grade_level_dim') subject_abbr = serializers.CharField(source='subject_abbr_dim') product_id = serializers.IntegerField(source='dim_id') product_title = serializers.CharField(source='title_dim') ratings = serializers.SerializerMethodField() class Meta: model = Table2 fields = [ 'grade_level', 'subject', 'subject_abbr', 'product_id', 'product_title', 'ratings' ] def get_ratings(self,obj): # 直接查询当前课程对应的所有评级记录,避免全表扫描 rating_records = Table3.objects.filter( title=obj.title_dim, grade_level=obj.grade_level, subject_abbr=obj.subject_abbr_dim, source__in=['Org1', 'Org2'] ) # 按机构分组,同一机构的记录合并为一个评级项 rating_map = {} for record in rating_records: source = record.source if source not in rating_map: rating_map[source] = { "review_org": source, "review_url": record.report_url, "review_items": [] } # 序列化单个评级子项 item_serializer = reportSerializer(record) rating_map[source]['review_items'].append(item_serializer.data) # 按Org1、Org2的顺序返回,没有数据的机构返回空数组 ratings = [] for org in ['Org1', 'Org2']: if org in rating_map: ratings.append(rating_map[org]) else: ratings.append({ "review_org": org, "review_url": "", # 无数据时可填默认值或留空 "review_items": [] }) return ratings class reportSerializer(ModelSerializer): class Meta: model = Table3 fields = ['name', 'value', 'label', 'label_color'] class DistrictDetailSerializer(ModelSerializer): curriculum = serializers.SerializerMethodField() class Meta: model = Table1 exclude = ('finance_total', 'revenue_total') def get_curriculum(self, obj): # 查询当前主体关联的所有课程 course_queryset = Table2.objects.filter(id=obj.id).distinct('col1','col2') if not course_queryset.exists(): return {} serializer = CurriculumSerializer(course_queryset, many=True) curriculum_map = {} for d in serializer.data: key = f"{d['grade_level']} {d['subject_abbr']}" if key in curriculum_map: curriculum_map[key].append(d) else: curriculum_map[key] = [d] return curriculum_map
核心修改说明
- 重构了
get_ratings方法,直接获取当前课程关联的所有评级记录,按机构分组生成数组元素,避免全表查询,性能提升明显 - 移除了冗余的
RatingsSerializer,直接手动构造符合要求的评级对象结构,完全匹配目标格式的层级 - 空值统一返回空数组,替换原有的字符串
'null',符合JSON规范 - 字段名已按目标格式做映射调整,无需额外处理
内容的提问来源于stack exchange,提问作者Abdul
相关产品推荐
相关产品推荐

