web-dev-qa-db-ja.com

Django Rest Frameworkを使用して単一フィールドをパッチする方法は?

多くのフィールドを持つモデル「MyModel」があり、PATCHメソッドを使用してフィールド「status」を更新したいと思います。クラスベースのビューを使用しています。 PATCHを実装する方法はありますか?

35
pnhegde

シリアライザーでは、 partial=True シリアライザーを初期化するとき。これが PATCHリクエストの処理方法 デフォルトで 汎用ビューで です。

serializer = CommentSerializer(comment, data=request.data, partial=True)

これにより、標準のPUTリクエストの制限なしに、シリアライザーの個々のフィールド、または必要に応じてすべてのフィールドを更新できます。

35
Kevin Brown

Kevin Brown が述べたように、 chefarov がうまく明確になったpartial=Trueを使用できます。

修正したいのですが、使用しているHTTPメソッドに応じて、ジェネリックを自由に使用できると言います。

  • 要求されたようなPATCH HTTPメソッドを使用している場合は、そのまま使用できます。 partial_updateUpdateModelMixinコードを見ることができます:

    def partial_update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return self.update(request, *args, **kwargs)
    
  • PATCHとは異なるHTTPメソッドの場合、次のようにget_serializerメソッドをオーバーライドするだけでこれを実現できます。

    def get_serializer(self, *args, **kwargs):
        kwargs['partial'] = True
        return super(YOUR_CLASS, self).get_serializer(*args, **kwargs)
    

これにより、シリアライザーが部分的に作成され、残りのジェネリックは、update/partial_updateメカニズムに手動で介入することなく、チャームのように機能します。

フードの下

私はジェネリックを使用しました:generics.UpdateAPIViewこのコードを持つUpdateModelMixinを使用します:

def update(self, request, *args, **kwargs):
    partial = kwargs.pop('partial', False)
    instance = self.get_object()
    serializer = self.get_serializer(instance, data=request.data, partial=partial)
    …

そのため、get_serializer関数をオーバーライドする場合、実際に部分引数をオーバーライドして、強制的にtrueにすることができます。

一部のHTTPメソッドに対してのみ部分的にしたい場合、このアプローチはより困難になることに注意してください。

私はdjangorestframework == 3.5.3を使用しています

13
Uri Shalit

すぐにサポートされるようです。ブラウザーAPIで、モデルの詳細ページに移動し、HTML Formタブの横にあるRaw dataをクリックして、IDフィールドと変更するフィールドを除くすべてをJSON文字列から削除します。 PATCHをクリックします。部分的なPATCH更新が実行されます。

私はdjangorestframework==3.2.4を使用しており、これを有効にするためにViewSetとSerializerに何もする必要はありません。

この例では、モデルのbool status_fieldフィールドを更新しており、jquery 2.2.1を使用しています。以下を<head>に追加します。

<script src="{% static 'my_app/jquery.min.js' %}"></script>
<script>
$(document).ready(function(){
    var chk_status_field = $('#status_field');
    chk_status_field.click(function(){
        $.ajax({url: "{% url 'model-detail' your_rendering_context.id %}",
            type: 'PATCH', timeout: 3000, data: { status_field: this.checked }
        })
        .fail(function(){
            alert('Error updating this model instance.');
            chk_status_field.prop('checked', !chk_status_field.prop('checked'));
        });
    });
});
</script>

次に<form>で:

<input type="checkbox" id="status_field" {% if your_rendering_context.status_field %} 
    checked {% endif %} >

チェックボックスの変更を許可し、失敗した場合は元に戻すことを選択しました。しかし、clickmousedownに置き換えて、AJAX呼び出しが成功した場合にのみチェックボックスの値を更新することができます。ただし、接続が遅い場合。

5
Chris

ビューの多くを変更せずにModelSerializerを使用して簡単なソリューションを探している場合は、ModelSerializerをサブクラス化して、すべてのModelSerializersを継承させることができます。

class PatchModelSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        kwargs['partial'] = True
        super(PatchModelSerializer, self).__init__(*args, **kwargs)

class ArticleSerializer(PatchModelSerializer):
    class Meta:
        model = Article
4
firecast

私はしばらくこれに苦労しましたが、これは汎用ビューまたは汎用ビューとミックスインの組み合わせを使用した非常に簡単な実装です。

汎用更新ビュー(generics.UpdateAPIView)を使用する場合は、次のコードを使用して、リクエストタイプがPATCHであることを確認してください。

class UpdateUser(generics.UpdateAPIView):

    queryset = User.objects.all()
    serializer_class = UserSerializer

他に何もありません!

更新ミックスイン(mixins.UpdateModelMixin)を汎用ビュー(generics.GenericAPIView)と組み合わせて使用​​している場合は、次のコードを使用して、リクエストタイプがPATCHであることを確認してください。

class ActivateUser(mixins.UpdateModelMixin, generics.GenericAPIView):

    serializer_class = UserSerializer
    model = User
    lookup_field = 'email'

    def get_queryset(self):
        queryset = self.model.objects.filter(active=False)
        return queryset

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

2番目の例はより複雑で、クエリセットとルックアップフィールドをオーバーライドする方法を示していますが、注意が必要なコードはパッチ関数です。

0
user2583728