Say I have Django models like this:
class Book(models.Model):
title = models.CharField(max_length=150)
author = models.CharField(max_length=150)
class Chapter(models.Model):
book = models.ForeignKey(Book, related_name='chapters')
title = models.CharField(max_length=150)
page_num = models.IntegerField()
and Django Rest Framework classes like this:
class ChapterSerializer(serializers.ModelSerializer):
class Meta:
model = Chapter
fields = ('id', 'title', 'page_num')
class BookSerializer(serializers.ModelSerializer):
chapters = ChapterSerializer(many=True)
class Meta:
model = Book
fields = ('id', 'title', 'author', 'chapters')
def create(validated_data):
chapters = validated_data.pop('chapters')
book = Book(**validated_data)
book.save()
serializer = ChapterSerializer(data=chapters, many=True)
if serializer.is_valid(raise_exception=True):
chapters = serializer.save()
class BookCreate(generics.CreateAPIView):
serializer = BookSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
serializer.save()
# Do some other stuff
and I POST some JSON like this:
{
title: "Test book",
author: "Test author",
chapters: [
{title: "Test chapter 1", page_num: 1},
{title: "Test chapter 2", page_num: 5}
]
}
I get an exception because chapter
doesn't have a book
associated with it. If I add book
as one of the fields of ChapterSerializer
, then the JSON will fail to validate because the BookSerializer
in BookCreate
won't validate because it will expect a book id for the chapters, but the book hasn't been created yet. How do I resolve this situation?
Is there a way to have the BookSerializer
to validate its own fields and not to validate its chapter
's?
You can pass additional arguments on .save
. So I think you just need to pass the newly created book instance to the serializer
, e.g.
def create(validated_data):
chapters = validated_data.pop('chapters')
book = Book(**validated_data)
book.save()
serializer = ChapterSerializer(data=chapters, many=True)
if serializer.is_valid(raise_exception=True):
chapters = serializer.save(book=book)
I think, you should not create another Serializer inside the create()
method of a serializer because this is redundant. The validation has already been done by the serializer if you defined it to be the serializer for the model referenced by this field:
class BookSerializer(serializers.ModelSerializer):
# here you define the serializer to validate your input
chapters = ChapterSerializer(many=True)
instead you can just create the object, the data has already been validated by the call to is_valid()
of the initial serializer. you need to pass the book to the create()
method anyways:
def create(validated_data):
chapters_data = validated_data.pop('chapters')
book = Book.objects.create(**validated_data)
for chapter_data in chapters_data:
Chapter.objects.create(book=book, **chapter_data)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With