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

Django使用serializers创建带关联对象的实例时报期望字典错误如何解决

问题根因
  1. 你在AdsSerializer中显式声明了display = DisplaySerializer(),嵌套序列化器在反序列化(接收请求写入数据)时,默认要求传入完整的嵌套字典数据,用于创建/更新关联的Displays对象,而你期望的是传入已有Displays对象的id进行关联,二者不匹配,所以触发类型错误。
  2. 你之前同类需求能正常传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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 15:54:05