Django DRF嵌套序列化器validated_data嵌套字段返回空OrderedDict问题
问题根因
你遇到的嵌套字段反序列化后为空的核心原因是:DRF的ModelSerializer会默认将模型主键(pk)字段设为只读(read_only=True)。
你定义的OrganisationNameSerializer、EventTypeSerializer仅声明了pk作为唯一字段,而该字段的只读属性会导致反序列化(写入)阶段直接忽略传入的pk值,最终validated_data里的嵌套字段就只剩下空的OrderedDict。
你序列化已存在的实例时输出正常,是因为只读字段仅在反序列化阶段被忽略,序列化(读取)阶段仍会正常输出。
你触发的KeyError是因为你手动移除了validated_data里的嵌套字段后,序列化器创建实例时没有对应字段值,后续返回响应序列化时找不到对应属性导致的。
解决方法
你仅需要通过pk关联已有资源,不需要通过当前接口创建嵌套的EventType/Organisation实例,推荐采用DRF官方最佳实践,区分读写字段逻辑:
方案1:使用PrimaryKeyRelatedField处理写入,嵌套序列化器处理读取(推荐)
修改NewsEventSerializer如下:
class NewsEventSerializer(ModelSerializer): # 读取时输出嵌套结构,设为只读 event_type = EventTypeSerializer(read_only=True) author = OrganisationNameSerializer(read_only=True) subject_companies = OrganisationNameSerializer(many=True, read_only=True) # 写入时用主键关联,设为只写,source指向对应模型字段 event_type_id = serializers.PrimaryKeyRelatedField( queryset=EventType.objects.all(), write_only=True, source='event_type' ) author_id = serializers.PrimaryKeyRelatedField( queryset=Organisation.objects.all(), write_only=True, source='author' ) subject_companies_ids = serializers.PrimaryKeyRelatedField( queryset=Organisation.objects.all(), many=True, write_only=True, source='subject_companies' ) class Meta: model = NewsEvent fields = [ 'pk', 'event_type', 'author', 'event_date', 'event_time', 'disclosed_at', 'subject_companies', 'created_at', 'updated_at', # 写入字段也要加入fields列表 'event_type_id', 'author_id', 'subject_companies_ids' ] def create(self, validated_data): # 这里validated_data已经自动填充了event_type、author、subject_companies实例 # 不需要自己手动查pk对应的对象,直接创建即可 return super().create(validated_data)
该方案的优势是DRF会自动校验传入的pk是否存在,不存在会直接返回400错误,不需要你手动捕获异常处理。
方案2:修改嵌套序列化器的pk字段为可写
如果一定要用嵌套结构同时处理读写,手动声明pk字段覆盖默认的只读属性即可:
class OrganisationNameSerializer(ModelSerializer): # 显式声明pk为可写字段 pk = serializers.IntegerField() class Meta: model = Organisation fields = ['pk'] class EventTypeSerializer(ModelSerializer): pk = serializers.IntegerField() class Meta: model = EventType fields = ['pk']
修改后你需要在create方法里手动解析嵌套字段的pk,查询对应实例再赋值给NewsEvent:
def create(self, validated_data): # 手动解析嵌套字段 event_type_data = validated_data.pop('event_type') author_data = validated_data.pop('author') subject_companies_data = validated_data.pop('subject_companies') validated_data['event_type'] = EventType.objects.get(pk=event_type_data['pk']) validated_data['author'] = Organisation.objects.get(pk=author_data['pk']) news_event = NewsEvent.objects.create(**validated_data) # 多对多字段需要单独添加 for company_data in subject_companies_data: news_event.subject_companies.add(Organisation.objects.get(pk=company_data['pk'])) return news_event
内容的提问来源于stack exchange,提问作者allinws
相关产品推荐
相关产品推荐

