Django使用serializers创建带关联对象的实例时报期望字典错误如何解决
问题根因
- 你在
AdsSerializer中显式声明了display = DisplaySerializer(),嵌套序列化器在反序列化(接收请求写入数据)时,默认要求传入完整的嵌套字典数据,用于创建/更新关联的Displays对象,而你期望的是传入已有Displays对象的id进行关联,二者不匹配,所以触发类型错误。 - 你之前同类需求能正常传id是因为当时没有配置嵌套序列化器,Django REST Framework默认会对外键字段使用
PrimaryKeyRelatedField,支持直接传入id进行关联。
另外你现有代码还存在两处笔误:
AdsDj模型类末尾多了一行无效的null=True,需要删除- 序列化器
Meta中的model属性和你定义的模型类名不匹配:AdsSerializer中写的是model=Ads但实际模型是AdsDj,OrderSerializer中写的是model=Orders但实际模型是OrdersDj,不修正会引发后续其他报错。
解决办法
根据你的业务需求选择对应方案即可:
方案1:仅需要关联已有Displays对象,接口返回时要展示display完整详情
这是最常见的业务场景,修改AdsSerializer如下:
class AdsSerializer(serializers.ModelSerializer): # 嵌套序列化器仅用于读取返回,设置read_only=True不参与写入校验 display = DisplaySerializer(read_only=True) # 新增写入专用字段,接受id关联已有Displays对象 display_id = serializers.PrimaryKeyRelatedField( queryset=Displays.objects.all(), source='display', write_only=True ) class Meta: model = AdsDj # 修正模型类名匹配 fields = "__all__"
修改后请求参数保持传入display_id: 10即可正常完成关联。
方案2:不需要返回display完整详情,仅需要返回id
直接删除AdsSerializer中display = DisplaySerializer()这一行即可,DRF默认会对display外键字段使用主键关联逻辑,直接传display: 10就能正常写入。
方案3:需要同时支持传入id关联已有对象、传入字典创建新的Displays对象
自定义支持两种传入格式的关联字段即可:
class FlexibleRelatedField(serializers.PrimaryKeyRelatedField): def __init__(self, **kwargs): self.nested_serializer = kwargs.pop('nested_serializer', None) if self.nested_serializer and not issubclass(self.nested_serializer, serializers.Serializer): raise TypeError('nested_serializer参数必须是Serializer子类') super().__init__(**kwargs) def to_representation(self, value): if self.nested_serializer: return self.nested_serializer(value, context=self.context).data return super().to_representation(value) class AdsSerializer(serializers.ModelSerializer): display = FlexibleRelatedField( queryset=Displays.objects.all(), nested_serializer=DisplaySerializer ) class Meta: model = AdsDj fields = "__all__"
修改后传display: 10(关联已有)或者display: {"xxx":"xxx"}(新建对象)都可以正常处理。
内容的提问来源于stack exchange,提问作者kakakakakakakk
相关产品推荐
相关产品推荐

