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

DRF提交嵌套JSON报错:Country.generalInfo需GeneralInfo实例

提交嵌套JSON到DRF /countries/接口报错

提交的JSON数据

{"name": "Country Name","description": "Description here...","generalInfo": {"capital": "Capital","population": "Population","highestPeak": "HighestPeak","area": "Area"},"timelineData": [{"name": "Name 1","ruler": "Ruler","dateStart": "dateStart","dateEnd": "dateEnd","description": "description"},{"name": "Name 2","ruler": "Ruler","dateStart": "dateStart","dateEnd": "dateEnd","description": "description"},{"name": "Name 3","ruler": "Ruler","dateStart": "dateStart","dateEnd": "dateEnd","description": "description"}]}

错误信息

ValueError at /countries/
Cannot assign "OrderedDict([('capital', 'Capital'), ('population', 'Population'), ('highestPeak', 'HighestPeak'), ('area', 'Area')])": "Country.generalInfo" must be a "GeneralInfo" instance.

Request Method: POST
Request URL: http://127.0.0.1:8000/countries/
Django Version: 4.0.3

现有代码

models.py

class GeneralInfo(models.Model):  
    capital = models.CharField(max_length=200)
    population = models.CharField(max_length=200)
    highestPeak = models.CharField(max_length=200)
    area = models.CharField(max_length=200)

class TimelineData(models.Model):
    name = models.CharField(max_length=200)
    ruler = models.CharField(max_length=200)
    dateStart = models.CharField(max_length=200)
    dateEnd = models.CharField(max_length=200)
    description = models.TextField(default='Description here...')

class Country(models.Model):
    name = models.CharField(max_length=200, db_index=True)
    description = models.TextField(default='Description here...')
    generalInfo = models.ForeignKey(GeneralInfo, on_delete=models.CASCADE)
    timelineData = models.ManyToManyField(TimelineData)

serializers.py

class TimelineDataSerializer(serializers.ModelSerializer):
    class Meta:
        model = TimelineData
        fields= '__all__'

class GeneralInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model= GeneralInfo
        fields = '__all__'

class CountrySerializer(serializers.ModelSerializer):
    timelineData = TimelineDataSerializer(many=True)
    generalInfo = GeneralInfoSerializer()
    class Meta:
        model= Country
        fields = '__all__'
    def create(self, validated_data):
        timelineData = validated_data.pop('timelineData')
        country = Country.objects.create(**validated_data)
        for timelineItem in timelineData:
            TimelineData.objects.create(country=country,**timelineItem)
        return country

views.py

class CountryList(viewsets.ModelViewSet):
    serializer_class = CountrySerializer
    queryset = Country.objects.all()

解决方法

错误核心原因:Country.generalInfo是ForeignKey字段,要求传入GeneralInfo模型实例,但原代码直接把JSON解析后的字典传给了Country.objects.create(),导致类型不匹配。另外timelineData是ManyToMany关系,原代码尝试在创建TimelineData时直接关联country,但TimelineData模型本身没有外键指向Country,这种写法不成立。

修改serializers.py中的create方法即可解决:

class TimelineDataSerializer(serializers.ModelSerializer):
    class Meta:
        model = TimelineData
        fields= '__all__'

class GeneralInfoSerializer(serializers.ModelSerializer):
    class Meta:
        model= GeneralInfo
        fields = '__all__'

class CountrySerializer(serializers.ModelSerializer):
    timelineData = TimelineDataSerializer(many=True)
    generalInfo = GeneralInfoSerializer()
    class Meta:
        model= Country
        fields = '__all__'
    
    def create(self, validated_data):
        # 先创建GeneralInfo实例,替换validated_data中的字典
        general_info_data = validated_data.pop('generalInfo')
        general_info = GeneralInfo.objects.create(**general_info_data)
        validated_data['generalInfo'] = general_info
        
        # 取出TimelineData列表,后续单独处理
        timeline_items = validated_data.pop('timelineData')
        
        # 创建Country实例
        country = Country.objects.create(**validated_data)
        
        # 批量创建TimelineData并关联到Country
        timeline_instances = [TimelineData.objects.create(**item) for item in timeline_items]
        country.timelineData.add(*timeline_instances)
        
        return country

关键修改点:

  1. 处理GeneralInfo:先从验证后的数据中取出generalInfo字典,创建对应的GeneralInfo实例,再将实例放回validated_data,确保创建Country时传入正确的关联对象。
  2. 处理TimelineData:先批量创建所有TimelineData实例,再通过add(*timeline_instances)方法将它们关联到已创建的Country实例(ManyToMany关系需要这种关联方式)。

内容的提问来源于stack exchange,提问作者Oleksandr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:35:33