Чтобы проверить вложенный объект с помощью вложенного сериализатора:
@transaction.atomic
def create(self, validated_data):
pages_data = validated_data.pop('pages') #pages data of a book
book= self.Meta.model.objects.create(**validated_data)
for page_data in pages_data:
page = Page(book=book)
page_serializer = PageSerializer(page, data = page_data)
if page_serializer.is_valid(): #PageSerializer does the validation
page_serializer.save()
else:
raise serializers.ValidationError(page_serializer.errors) #throws errors if any
return book
Предположим, вы отправляете данные как:
{
"title": "Book Title",
"pages": [{
"link":2,#<= this one here
"page_no":52,
"text":"sometext"}]
}
В приведенных выше данных мы отправляем id
объекта Link
. Но в методе create
для BookSerializer
, определенного выше, данные, которые мы отправили, изменяются на:
{
"title": "Book Title",
"pages": [{
"link":Link Object (2),#<= changed to the Link object with id 2
"page_no":52,
"text":"sometext"}]
}
А PageSerializer
фактически предназначен для получения pk
значения link
, т. Е. "link": 2
вместо "link":Link Object (2)
. Отсюда выдает ошибку:
{
"link": [
"Incorrect type. Expected pk value, received Link."
]
}
Таким образом, обходной путь заключается в переопределении метода to_internal_value
вложенного сериализатора для преобразования полученного объекта Link Object (2)
в его значение pk
.
Итак, ваш PageSerializer
класс должен быть:
class PageSerializer(serializers.ModelSerializer):
class Meta:
model = Page
fields = ('link','text','page_no')
def to_internal_value(self, data):
link_data = data.get("link")
if isinstance(link_data, Link): #if object is received
data["link"] = link_data.pk # change to its pk value
obj = super(PageSerializer, self).to_internal_value(data)
return obj
def validate_text(self, value):
#some validation is done here.
def validate_link(self, value):
#some validation is done here.
и родительский сериализатор:
class BookSerializer(serializers.ModelSerializer):
pages = PageSerializer(many=True)
class Meta:
model = Book
fields = ('title','pages')
@transaction.atomic
def create(self, validated_data):
pages_data = validated_data.pop('pages')#pages data of a book
book= self.Meta.model.objects.create(**validated_data)
for page_data in pages_data:
page = Page(book=book)
page_serializer = PageSerializer(page, data = page_data)
if page_serializer.is_valid(): #PageSerializer does the validation
page_serializer.save()
else:
raise serializers.ValidationError(page_serializer.errors) #throws errors if any
return book
Это должно позволить вложенному сериализатору выполнять проверку вместо записи проверки внутри метода create родительского сериализатора и нарушения DRY.