I have a serializer BookSerializer
of model Book
with a nested PageSerializer
of model Page
. Updating of a Book
instance involves deleting all its Page
instances followed by creation of these Page
instances, maybe with or without this updation involving some new data of pages or nothing or existing.
But my Book
model holds a constraint where each Book
instance can only have max 100
pages each. And the validation check is done inside the PageSerializer
's validate
method. I have another reason to do this here:
def validate(self, attrs):
#some logic here
raise some error if book instance already has 100 pages or if it will have more than 100 pages when combined with new pages when added.
The update method definition of a serializer or say BookSerializer
is:
def update(self, instance, validated_data):
...
...
So, the data being sent to update is already being validated and can be accessed as validated_data
inside the update
method.
Now, here's the problem. The nested serializer PageSerializer
has a validate
method which checks how many pages of that Book
instance are already there and validates against them.
Let B
be an instance of Book
already having 100
pages. If I try to udate B
without any changes, the data sent is still checked for validation in the BookSerializer
, passing its pages data to PageSerializer
and then finally passing the validated_data
to update(self, instance, val;idated_data)
method.
My questions are:
B
before validating data of pages sent for updation of B
? I recommend you to you to delete pages in update(**kwargs)
method of BookSerializer. In validation method of PageSerializer
you should validate received data(you should not consider existed pages as a sequence you will delete all them ). It is a case for only fully overriding pages of existed book. But when you want to update them you should also return id
(you should add id
in PageSerializer
in order nested serializer can identify that you are updating an instance) of pages. So validation will be required in order to update.
Request body should be like this:
{
'book_title': 'TITLE'
'pages':[
{'id': 3, 'title': 'TITLE', 'body': 'BODY'},
{'title': 'TITLE', 'body': 'BODY'}, ...
]
....
}
class PageSerializer(serializers.ModelSerializer):
class Meta:
model = Page
fields =['id', .....]
class Book(serializers.ModelSerializer):
pages = PageSerializer(many=True)
class Meta:
model = Book
fields = ['id', 'pages', ....]
def validate_pages(self, values): # here values will be as [{...},{...},..]
obj_list = list()
for value in values:
pk = value.pop('id', None)
if pk:
try:
page = Page.objects.get(pk=pk)
for k, v in value.items():
setattr(page, key, value)
obj_list.append(page)
except Page.DoesNotExists():
# handle by yourself, skip or raise error
else:
obj_list.append(Page(**value))
# here you can validate length also
return obj_list
And in create(self, validated_data)
and update(self, instance, validated_data)
you get pages as object list. So you can delete using this:
pages = validated_data['pages']
page_ids = [page.pk for page in pages if page.pk] # it get all ids from list
if page_ids:
Page.objects.filter(book=instance).exclude(pk__in=page_ids).delete() it can be applicable only for updating
And simple creation using bulk or iteration.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.