使用 django-rest-framework 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,并为page给定的每个序列号book创建一个新页面或更新(如果存在)。
page
book
class RequestSerializer(serializers.Serializer): book_id = serializers.IntegerField() page = PageSerializer(many=True) class PageSerializer(serializers.ModelSerializer): class Meta: model = Page
我知道用实例化序列化程序instance会更新当前序列化程序,但是如何在create嵌套序列化程序的方法中使用它呢?
instance
create
首先,您要支持创建新的图书实例还是仅更新现有的图书实例?
如果您只想创建新的图书实例,则可以执行以下操作…
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此处添加。在创建图书实例时,我们不会包含图书ID。当我们更新图书实例时,通常会将图书ID包含在URL中,而不是包含在请求数据中。
book_id
如果你想支持创建和书籍实例的更新,那么你需要考虑一下你要如何处理未包含在请求页面,但 在 当前与书实例相关联。
您可能会选择静默忽略那些页面并保持原样,或者想引发验证错误,或者想要删除它们。
假设您要删除请求中未包含的所有页面。
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()方法。
update()
您还可以通过多种方式减少查询数量,例如。使用批量创建/删除操作,但以上操作将以非常简单的方式完成工作。
如您所见,在处理嵌套数据时,您可能想要的行为类型有些微妙,因此,请仔细考虑在各种情况下期望的行为。
另请注意,我Serializer在上面的示例中一直使用而不是ModelSerializer。在这种情况下,仅将所有字段显式包括在serializer类中,而不是依赖ModelSerializer默认情况下自动生成的一组字段,会更简单。
Serializer
ModelSerializer