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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 04:36:03