django-rest-framework 3.0在嵌套序列化器中创build或更新

Django的其余框架3.0,并有这些简单的模型:

class Book(models.Model): title = models.CharField(max_length=50) class Page(models.Model): book = models.ForeignKey(Books, related_name='related_book') text = models.CharField(max_length=500) 

鉴于这个JSON请求:

 { "book_id":1, "pages":[ { "page_id":2, "text":"loremipsum" }, { "page_id":4, "text":"loremipsum" } ] } 

我如何编写一个嵌套的序列化程序来处理这个JSON,给定的book每个page可以创build一个新的页面或更新(如果存在)。

 class RequestSerializer(serializers.Serializer): book_id = serializers.IntegerField() page = PageSerializer(many=True) class PageSerializer(serializers.ModelSerializer): class Meta: model = Page 

我知道用实例实例化序列化器会更新当前的序列化器,但是如何在嵌套序列化器的create方法中使用它?

首先,你想支持创build新的书籍实例,还是只更新现有的实例?

如果你只是想创build新的书籍实例,你可以做这样的事情…

 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 。 当我们创build书籍实例时,我们不会包含书籍ID。 当我们更新图书实例时,我们通常会将书籍ID包含在URL中,而不是在请求数据中。

如果您希望同时支持书籍实例的创build和更新,则需要考虑如何处理未包含在请求中但当前与书籍实例关联的页面。

您可能会select默默忽略这些页面,并保持原样,您可能需要提出validation错误,或者您可能要删除它们。

假设您要删除未包含在请求中的任何页面。

 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 

您也可能只想支持书籍更新,而不支持创build,在这种情况下, 包含update()方法。

还有各种方法可以减less查询的数量,例如。 使用批量创build/删除,但上述将以相当简单的方式完成这项工作。

正如您所看到的,在处理嵌套数据时,您可能需要的行为types中存在细微差别,所以请仔细考虑您在各种情况下所期望的行为。

另外请注意,我在上面的例子中使用了Serializer而不是ModelSerializer 。 在这种情况下,只需要显式包含序列化类中的所有字段,而不是依靠ModelSerializer默认生成的自动字段ModelSerializer可以了。