【问题标题】:django-rest-framework 3.0 create or update in nested serializerdjango-rest-framework 3.0 在嵌套序列化程序中创建或更新
【发布时间】:2015-02-10 15:07:12
【问题描述】:

使用 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 创建一个新页面或更新(如果存在)。

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


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

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

【问题讨论】:

    标签: python json django serialization django-rest-framework


    【解决方案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。当我们创建书籍实例时,我们不会包含书籍 ID。当我们更新图书实例时,我们通常会将图书 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 默认生成的自动字段集。

    【讨论】:

    【解决方案2】:

    您可以简单地使用drf-writable-nested。 它会自动使您的嵌套序列化程序可写和可更新。

    在你serializers.py:

    from drf_writable_nested import WritableNestedModelSerializer
    
    class RequestSerializer(WritableNestedModelSerializer):
        book_id = serializers.IntegerField()
        page = PageSerializer(many=True)
    
    
    class PageSerializer(serializers.ModelSerializer):
        class Meta:
            model = Page
    

    就是这样!

    此外,如果您不需要同时使用 createupdate 逻辑,该库还支持仅使用其中之一。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-09
    • 2017-01-28
    • 1970-01-01
    • 2018-10-26
    • 2018-07-14
    • 2015-11-09
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多