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
可以了。