Вложенный объект 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',
# }