web-dev-qa-db-ja.com

django-rest-framework 3.0は、ネストされたシリアライザーで作成または更新します

Django-rest-framework 3.で、これらの単純なモデルを使用する場合:

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を処理し、特定のpagebookごとにネストされたシリアライザーを作成して、新しいページを作成するか、存在する場合は更新する方法はありますか。

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


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

instanceでシリアライザーをインスタンス化すると現在のものが更新されることを知っていますが、ネストされたシリアライザーのcreateメソッド内でどのように使用する必要がありますか?

70
norbertpy

まず、新しいブックインスタンスの作成をサポートしますか、それとも既存のインスタンスの更新のみをサポートしますか?

新しい本のインスタンスを作成したいだけなら、次のようなことができます...

_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
_

Iはここに_book_id_を含めていないことに注意してください。本のインスタンスを作成するとき、本のIDは含めません。書籍のインスタンスを更新する場合、通常、リクエストデータではなく、URLの一部として書籍IDを含めます。

ブックインスタンスの作成と更新の両方をサポートする場合は、リクエストに含まれていないがare現在関連付けられているページをどのように処理するかを考える必要があります本のインスタンス。

これらのページを静かに無視してそのままにしておくか、検証エラーを発生させるか、削除することができます。

リクエストに含まれていないページを削除したいとします。

_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
_

また、onlyブックの更新をサポートし、作成をサポートしない場合もあります。その場合、onlyupdate()メソッド。

また、クエリの数を減らすことができるさまざまな方法があります。一括作成/削除を使用しますが、上記はかなり簡単な方法でジョブを実行します。

ご覧のとおり、ネストされたデータを処理する際に必要な動作の種類には微妙な点があるため、さまざまな場合に期待される動作を正確に検討してください。

また、上記の例ではSerializerではなくModelSerializerを使用していることに注意してください。この場合、デフォルトでModelSerializerが生成するフィールドの自動セットに依存するのではなく、シリアライザークラスのすべてのフィールドを明示的に含める方が簡単です。

95
Tom Christie

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

以上です!

また、ライブラリは、createロジックとupdateロジックの両方を必要としない場合に、どちらか一方のみの使用をサポートします。

0
Peter Sobhi