Вложенный объект DRF post

Я пытаюсь опубликовать этот 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)

Я также переопределил метод create для CountrySerializer и вот мой 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()

Я новичок в Django и Python, поэтому, возможно, я что-то упустил. Я застрял на этом уже некоторое время и не смог найти никакого решения самостоятельно

Ошибка связана с тем, что OrderedDict должен быть фактическим GeneralInfo объектом...

Я не часто (или вообще не часто) использовал сериализаторы, но это было бы моим общим предположением из того, что я видел из похожих проблем:

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')

        # pop out data (so it's not in final create), filter for object
        generalInfoObj = GeneralInfo.objects.filter(**validated_data.pop('generalInfo')).first()
        #   ^ get or None (no crash, my preference)

        #  could also be:
        #   generalInfoObj = GeneralInfo.objects.get( ... ) 
        #       ^ - get or crash
        #   generalInfoObj, created = GeneralInfo.objects.get_or_create( ... )
        #       ^ get or create it

        # debugger
        print('generalInfoObj', type(generalInfoObj), generalInfoObj)


        country = Country.objects.create(**validated_data, GeneralInfo=generalInfoObj)
        for timelineItem in timelineData:
            TimelineData.objects.create(country=country,**timelineItem)
        return country

Если generalInfo отображается как массив кортежей, то с помощью List Comprehension
можно сделать примерно следующее (добавляю это на всякий случай)

generalInfoObj = GeneralInfo.objects.filter(**{i[0]:i[1] for i in validated_data.pop('generalInfo')}).first()

## breakdown:

# generalinfo = [('key0', val0'), ('key1', val1')]

dict = {}
for i in generalinfo:
    # i = ('key', 'value')
    dict[i[0]] = i[1]

# dict = {
#   'key0': 'val0',
#   'key1': 'val1',
# }
Вернуться на верх