Ответ 1
Во-первых, хотите ли вы поддерживать создание новых экземпляров книги или обновление только существующих?
Если вы только хотели создать новые экземпляры книг, вы могли бы сделать что-то вроде этого...
class PageSerializer(serializers.Serializer):
text = serializers.CharField(max_length=500)
class BookSerializer(serializers.Serializer):
page = PageSerializer(many=True)
title = serializers.CharField(max_length=50)
def create(self, validated_data):
# Create the book instance
book = Book.objects.create(title=validated_data['title'])
# Create or update each page instance
for item in validated_data['pages']:
page = Page(id=item['page_id'], text=item['text'], book=book)
page.save()
return book
Обратите внимание, что здесь я не включил book_id
. Когда мы создаем экземпляры книг, мы не будем включать идентификатор книги. Когда мы обновляем экземпляры книг, мы обычно включаем идентификатор книги как часть URL-адреса, а не в данные запроса.
Если вы хотите поддерживать как создание, так и обновление экземпляров книг, вам нужно подумать о том, как вы хотите обрабатывать страницы, которые не включены в запрос, но в настоящее время связаны с экземпляром книги.
Вы можете спокойно игнорировать эти страницы и оставить их такими, какие они есть, возможно, вы захотите поднять ошибку проверки, или вы можете удалить их.
Предположим, что вы хотите удалить любые страницы, не включенные в запрос.
def create(self, validated_data):
# As before.
...
def update(self, instance, validated_data):
# Update the book instance
instance.title = validated_data['title']
instance.save()
# Delete any pages not included in the request
page_ids = [item['page_id'] for item in validated_data['pages']]
for page in instance.books:
if page.id not in page_ids:
page.delete()
# Create or update page instances that are in the request
for item in validated_data['pages']:
page = Page(id=item['page_id'], text=item['text'], book=instance)
page.save()
return instance
Также возможно, что вы можете поддерживать только обновления книг, а не поддерживать создание, и в этом случае включать только метод update()
.
Существуют также различные способы сокращения числа запросов, например. используя объемное создание/удаление, но вышеуказанное выполнило бы работу довольно простым способом.
Как вы видите, есть тонкости в типах поведения, которые могут возникнуть при работе с вложенными данными, поэтому тщательно подумайте о том, какое поведение вы ожидаете в разных случаях.
Также обратите внимание, что я использовал Serializer
в приведенном выше примере, а не ModelSerializer
. В этом случае проще просто включить все поля в классе сериализатора явно, вместо того, чтобы полагаться на автоматический набор полей, которые ModelSerializer
генерирует по умолчанию.