Django Rest Framework非ORM模式下Serializer的source参数失效问题
问题本质
DRF的source参数仅在序列化输出阶段生效:即你将模型实例、字典等数据传入Serializer的instance参数(第一个位置参数)做数据读取时,source会指定从原始数据的哪个属性/键取值,映射到当前Serializer定义的字段名。
你当前处于反序列化输入阶段:传入的是data参数做数据校验和写入,这个阶段DRF只会用Serializer中定义的字段名去匹配传入payload的键,source参数不会参与这个阶段的键映射。
你的代码问题就在这里:Serializer中定义的校验字段名为no,但传入的payload里只有identifier键,没有no键,所以is_valid()实际会返回False,强制取instance.data['no']会抛出KeyError,并非source参数被忽略,而是用错了它的生效场景。
解决方案
根据不同的使用需求,可以选择对应实现方式:
需求1:反序列化接受identifier输入,序列化输出返回no字段
如果需要输入键为identifier,输出键为no,可以通过读写分离的字段配置实现:
class ProductSerializer(serializers.Serializer): # 反序列化专用:接受identifier输入,仅写阶段生效 identifier = serializers.CharField(write_only=True, required=True) # 序列化专用:输出为no,仅读阶段生效,source指定从identifier取值 no = serializers.CharField(source='identifier', read_only=True) product_name = serializers.CharField(required=False)
调用示例:
payload = { 'identifier': 'id-1', 'product_name': 'aaa' } # 第一步:反序列化校验输入 serializer = ProductSerializer(data=payload) serializer.is_valid(raise_exception=True) # 第二步:将校验后的数据做序列化输出,即可拿到no字段 output = ProductSerializer(instance=serializer.validated_data).data print(output['no']) # 输出:id-1
需求2:仅需反序列化时将输入的identifier映射为内部的no键
如果只需要反序列化阶段做键名映射,可以直接重写to_internal_value方法:
class ProductSerializer(serializers.Serializer): no = serializers.CharField(required=True) product_name = serializers.CharField(required=False) def to_internal_value(self, data): # 提前做键名映射 if 'identifier' in data: data['no'] = data.pop('identifier') return super().to_internal_value(data)
调用示例:
payload = {'identifier': 'id-1', 'product_name': 'aaa'} serializer = ProductSerializer(data=payload) serializer.is_valid(raise_exception=True) print(serializer.validated_data['no']) # 输出:id-1
内容的提问来源于stack exchange,提问作者Drachenfels
相关产品推荐
相关产品推荐

