DRF序列化器is_valid无报错,但validated_data为空(第三方API场景)
问题:DRF序列化器is_valid()返回True,但validated_data为空OrderedDict
在对第三方API返回的数据进行反序列化时,出现以下问题:
serializer.is_valid()返回True,且serializer.errors为空字典serializer.validated_data返回空的OrderedDict
但验证原始数据时,能够正常获取到id和code字段的值(示例输出:9 DZ)。
序列化器代码
from rest_framework import serializers class CountrySerializer(serializers.Serializer): countryId = serializers.SerializerMethodField() countryName = serializers.SerializerMethodField() def get_countryId(self, data): return data["id"] def get_countryName(self, data): return data["code"]
调用代码
from serializers import CountrySerializer import requests response = requests.get(url) jsonResponse = response.json() data = jsonResponse[0] serializer = CountrySerializer(data=data) # 执行输出 print(serializer.is_valid()) # 输出:True print(serializer.errors) # 输出:{} print(serializer.validated_data) # 输出:OrderedDict()
原因分析
SerializerMethodField是DRF中的只读字段,设计目的仅用于序列化过程(将Python对象转换为JSON格式),不会参与反序列化的字段验证和数据提取流程。
当使用CountrySerializer(data=data)进行反序列化时,DRF会自动忽略所有只读字段:
- 不对这些字段做校验,因此
is_valid()返回True - 不会将对应数据加入
validated_data,最终得到空的OrderedDict
解决方案
根据实际需求选择对应方案:
方案1:仅用于序列化(转换数据格式输出)
如果只是需要把第三方API返回的数据转换成指定格式(如将id映射为countryId,code映射为countryName),不需要反序列化校验,直接用instance参数初始化序列化器即可:
serializer = CountrySerializer(instance=data) print(serializer.data) # 输出示例:{'countryId': 9, 'countryName': 'DZ'}
方案2:需要反序列化并提取数据
如果要在反序列化过程中提取字段到validated_data,将SerializerMethodField替换为普通字段,通过source参数映射原始数据字段:
from rest_framework import serializers class CountrySerializer(serializers.Serializer): countryId = serializers.IntegerField(source='id') countryName = serializers.CharField(source='code')
此时执行反序列化:
serializer = CountrySerializer(data=data) serializer.is_valid() print(serializer.validated_data) # 输出示例:OrderedDict([('id', 9), ('code', 'DZ')])
如果需要validated_data直接用countryId和countryName作为键名,可重写validate方法:
class CountrySerializer(serializers.Serializer): id = serializers.IntegerField() code = serializers.CharField() def validate(self, attrs): attrs['countryId'] = attrs.pop('id') attrs['countryName'] = attrs.pop('code') return attrs
此时validated_data输出:
print(serializer.validated_data) # 输出示例:OrderedDict([('countryId', 9), ('countryName', 'DZ')])
内容的提问来源于stack exchange,提问作者Hanna
相关产品推荐
相关产品推荐

