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
关键修改点:
- 处理GeneralInfo:先从验证后的数据中取出
generalInfo字典,创建对应的GeneralInfo实例,再将实例放回validated_data,确保创建Country时传入正确的关联对象。 - 处理TimelineData:先批量创建所有
TimelineData实例,再通过add(*timeline_instances)方法将它们关联到已创建的Country实例(ManyToMany关系需要这种关联方式)。
内容的提问来源于stack exchange,提问作者Oleksandr
相关产品推荐
相关产品推荐

