0

I`m trying to post this json object

{
  "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"
    }
  ]
}

But I`m receiving this error

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

Here are my 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)

I have also overridden the create method for CountrySerializer and here are my 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

and views.py

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

I am new to Django and Python so maybe I missed something. I've been stuck on this for a while now and wasn't able to find any solution myself

1 Answer 1

1

The error is because that OrderedDict needs to be an actual GeneralInfo Object..

I have not used serializers much (or at all tbh), but this would be my general guess from what I've seen from similar problems:

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

If generalInfo shows up like an array of tuples, you'd do something like this with List Comprehension
(adding this just in case)

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',
# }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.