1. ホーム
  2. python

[解決済み] Django Rest Frameworkの部分更新

2023-01-24 07:25:40

質問

私は partial_update Django Rest フレームワーク を使用していますが、私は行き詰っているので、いくつかの明確化が必要です。

  1. なぜpartial=Trueを指定する必要があるのでしょうか?

    私の理解では、Demo オブジェクトの更新は partial_update メソッドの中で簡単に更新できます。これの目的は何ですか?

  2. シリアライズされた変数の中身は何ですか?

    の内部には何があるのでしょうか? serialized の中の partial_update メソッドですか?それは Demo オブジェクトですか?裏でどのような関数が呼び出されているのでしょうか?

  3. ここでの実装をどのように終わらせるのでしょうか?

ビューセット

class DemoViewSet(viewsets.ModelViewSet):
    serializer_class = DemoSerializer

    def partial_update(self, request, pk=None):
        serialized = DemoSerializer(request.user, data=request.data, partial=True)
        return Response(status=status.HTTP_202_ACCEPTED)

<ブロッククオート

シリアライザ

class DemoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Demo
        fields = '__all__'

    def update(self, instance, validated_data):
        print 'this - here'
        demo = Demo.objects.get(pk=instance.id)
        Demo.objects.filter(pk=instance.id)\
                           .update(**validated_data)
        return demo

どのように解決するのですか?

私も以前、あなたと同じ疑問を持っていましたが、rest_frameworkのソースコードを掘り下げたところ、以下のような知見を得ましたので、お役に立てれば幸いです。

質問1について。なぜpartial=Trueを指定する必要があるのでしょうか?

この質問は、関連する HTTP 動詞 .

PUT : PUT メソッドは、対象リソースの現在のすべての表現をリクエストペイロードで置き換えます。

PATCH : PATCHメソッドは、リソースに部分的な変更を加えるために使われます。

一般的に言えば partial は、クライアントがビューにデータを送信する際に、モデル内のフィールドがフィールドバリデーションを行うために必要であるかどうかを確認するために使用されます。

例えば、私たちは Book というモデルがあったとして、plsは両方の nameauthor_name のフィールドは 必須 (not null & not blank)です。

class Book(models.Model):
    name = models.CharField('name of the book', max_length=100)
    author_name = models.CharField('the name of the author', max_length=50)

# Create a new instance for testing
Book.objects.create(name='Python in a nut shell', author_name='Alex Martelli')

あるシナリオでは、モデルのフィールドの一部だけを更新する必要があるかもしれません。 name フィールドの Book . ですから、この場合、クライアントが送信するのは name フィールドをビューに送信します。クライアントからのデータ送信は次のようになります。

{"pk": 1, name: "PYTHON IN A NUT SHELL"}

しかし、このモデル定義では author_name を空白にすることはできません。そこで、私たちは partial_update の代わりに update . そのため、レストフレームワークでは フィールドのバリデーションチェック を実行しません。

テスト目的のために、両方のために2つのビューを作成することができます。 updatepartial_update というようにすれば、私が言ったことをもっと理解できるようになるでしょう。

views.py
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import UpdateModelMixin
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book


class BookUpdateView(GenericAPIView, UpdateModelMixin):
    '''
    Book update API, need to submit both `name` and `author_name` fields
    At the same time, or django will prevent to do update for field missing
    '''
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

class BookPartialUpdateView(GenericAPIView, UpdateModelMixin):
    '''
    You just need to provide the field which is to be modified.
    '''
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    def put(self, request, *args, **kwargs):
        return self.partial_update(request, *args, **kwargs)

urls.py
urlpatterns = patterns('',
    url(r'^book/update/(?P<pk>\d+)/$', BookUpdateView.as_view(), name='book_update'),
    url(r'^book/update-partial/(?P<pk>\d+)/$', BookPartialUpdateView.as_view(), name='book_partial_update'),
)

送信するデータ

{"pk": 1, name: "PYTHON IN A NUT SHELL"}

上記のjsonを送信すると /book/update/1/ に送信すると、HTTP_STATUS_CODE=400で以下のエラーが発生します。

{
  "author_name": [
    "This field is required."
  ]
}

しかし、上記のjsonを送信すると /book/update-partial/1/ に送信すると、HTTP_STATUS_CODE=200となり、以下のようなレスポンスが返ってきます。

{
  "id": 1,
  "name": "PYTHON IN A NUT SHELL",
  "author_name": "Alex Martelli"
}

質問2. シリアライズされた変数の中身は何ですか?

serialized はモデルインスタンスをシリアライズ可能なオブジェクトとしてラップしたもので、このシリアライズを利用して、プレーンなJSON文字列を serialized.data .

質問3について。ここでの実装はどのように仕上げるのでしょうか?

上の回答を読んだ時点で自分で答えられると思うのですが、どのタイミングで update を使うべきか、そして partial_update .

もし、まだ何か疑問があれば、遠慮なく質問してください。私はrest frameworkのソースコードを一部読んだだけで、あまり深く理解していない用語もあるかもしれませんので、間違っていたらご指摘ください...。