如何在Django REST Framework序列化器中设置动态键属性?
动态键结构的DRF序列化器实现方案
核心场景:你遇到的daySchedules是键为动态随机生成ID、值结构完全固定的字典对象,DRF没有内置字段直接适配这类场景,同时还要满足严格校验每个值的类型、结构的要求,具体实现分三步:
1. 先修正固定结构序列化器的字段映射
原始JSON的字段是驼峰命名,和你定义的蛇形字段不匹配,需要通过source指定映射关系,同时把模糊的ListField细化为明确的子序列化规则,满足你“明确指定每个属性类型”的要求:
# 定义服务时段的明确结构校验规则 class ServiceItemSerializer(serializers.Serializer): name = serializers.CharField() hours = serializers.DictField(child=serializers.CharField()) overnight = serializers.BooleanField() class ScheduleForDaySerializer(serializers.Serializer): schedule_name = serializers.CharField(source="scheduleName") services = serializers.ListField(child=ServiceItemSerializer()) open_time = serializers.CharField(source="openTime") close_time = serializers.CharField(source="closeTime")
2. 实现动态键的DaySchedulesSerializer
因为字典的键不固定,不需要硬编码任何键名,只需要遍历所有键值对,把每个值统一用上面定义的ScheduleForDaySerializer做校验和序列化即可,完全不关心键的具体取值:
class DaySchedulesSerializer(serializers.Serializer): def to_internal_value(self, data): # 先校验入参是字典结构 if not isinstance(data, dict): raise serializers.ValidationError("daySchedules必须是键值对结构") validated_data = {} # 逐一对每个值做严格结构校验 for key, value in data.items(): item = ScheduleForDaySerializer(data=value) if not item.is_valid(): # 把错误信息精确对应到出错的键下面 raise serializers.ValidationError({key: item.errors}) validated_data[key] = item.validated_data return validated_data def to_representation(self, instance): ret = {} for key, value in instance.items(): ret[key] = ScheduleForDaySerializer(value).data return ret
3. 补全最外层序列化器的字段映射
原始JSON的顶级键是驼峰结构,同样需要通过source指定和你定义的蛇形字段的对应关系,避免取不到值:
class WeekScheduleSerializer(serializers.Serializer): monday = serializers.CharField(allow_null=True, required=False) tuesday = serializers.CharField(allow_null=True, required=False) wednesday = serializers.CharField(allow_null=True, required=False) thursday = serializers.CharField(allow_null=True, required=False) friday = serializers.CharField(allow_null=True, required=False) saturday = serializers.CharField(allow_null=True, required=False) sunday = serializers.CharField(allow_null=True, required=False) class SchedulesSerializer(serializers.Serializer): day_schedules = DaySchedulesSerializer(source="daySchedules") week_schedule = WeekScheduleSerializer(source="weekSchedule")
使用方式
和你预期的调用逻辑完全一致,不需要做额外修改:
serializer = SchedulesSerializer(data=data) serializer.is_valid(raise_exception=True) # validated_data是经过严格校验、字段名标准化后的规整结构,原始的动态ID键会完整保留 response = serializer.data
注意事项
- 如果需要对动态键本身做格式校验(比如要求键是纯数字、固定长度),只需要在上面
to_internal_value的遍历循环里,加一层对key的格式判断即可,校验不通过直接抛错。 - 不要直接用默认
DictField实现这类结构:默认DictField只会校验值是基础JSON类型,不会做深层次的结构校验,达不到你要的严格类型约束的要求。
内容的提问来源于stack exchange,提问作者juicymango
相关产品推荐
相关产品推荐

