django-rest-framework 3.0 在嵌套序列化程序中创建或更新 [英] django-rest-framework 3.0 create or update in nested serializer

查看:49
本文介绍了django-rest-framework 3.0 在嵌套序列化程序中创建或更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 django-rest-framework 3.0 并拥有这些简单的模型:

With django-rest-framework 3.0 and having these simple models:

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 请求:

And given this JSON request:

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

如何编写嵌套序列化程序来处理此 JSON,并为给定 book 的每个 page 创建一个新页面或更新(如果存在).

How can I write a nested serializer to process this JSON and for each page for the given book either create a new page or update if it exists.

class RequestSerializer(serializers.Serializer):
    book_id = serializers.IntegerField()
    page = PageSerializer(many=True)


class PageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Page

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

I know that instantiating the serializer with an instance will update the current one but how should I use it inside the create method of nested serializer?

推荐答案

首先,您是要支持创建新的图书实例,还是仅更新现有的图书实例?

Firstly, do you want to support creating new book instances, or only updating existing ones?

如果您只想创建新书实例,您可以执行以下操作...

If you only ever wanted to create new book instances you could do something like this...

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 的一部分,而不是包含在请求数据中.

Note that I haven't included the book_id here. When we're creating book instances we won't be including a book id. When we're updating book instances we'll typically include the book id as part of the URL, rather than in the request data.

如果您想同时支持图书实例的创建和更新,那么您需要考虑如何处理未包含在请求中但当前与图书实例相关联的页面.

If you want to support both create and update of book instances then you need to think about how you want to handle pages that are not included in the request, but are currently associated with the book instance.

您可能会选择默默地忽略这些页面并保持原样,您可能想要引发验证错误,或者您可能想要删除它们.

You might choose to silently ignore those pages and leave them as they are, you might want to raise a validation error, or you might want to delete them.

假设您要删除请求中未包含的所有页面.

Let's assume that you want to delete any pages not included in the request.

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()方法.

It's also possible that you might want to only support book updates, and not support creation, in which case, only include the update() method.

还有多种方法可以减少查询次数,例如.使用批量创建/删除,但上面的方法会以相当简单的方式完成这项工作.

There are also various ways you could reduce the number of queries eg. using bulk create/deletion, but the above would do the job in a fairly straightforward way.

正如您所见,在处理嵌套数据时您可能需要的行为类型存在细微差别,因此请仔细考虑您在各种情况下期望的行为.

As you can see there are subtleties in the types of behavior you might want when dealing with nested data, so think carefully about exactly what behavior you're expecting in various cases.

另请注意,我在上面的示例中一直使用 Serializer 而不是 ModelSerializer.在这种情况下,只需显式包含序列化器类中的所有字段,而不是依赖 ModelSerializer 默认生成的自动字段集,就更简单了.

Also note that I've been using Serializer in the above example rather than ModelSerializer. In this case it's simpler just to include all the fields in the serializer class explicitly, rather than relying on the automatic set of fields that ModelSerializer generates by default.

这篇关于django-rest-framework 3.0 在嵌套序列化程序中创建或更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆