【DRF】PUTメソッドをPOSTメソッドの代わりに使う
Django REST FrameworkでPUT
メソッドでレコード(インスタンス)を作成したい場合
Django REST Framework(DRF)に限らず、REST APIでは通常、HTTPプロトコルのPOST
メソッドでインスタンス(=レコード)を作成してPUT
メソッドで更新をするが、PUT
で作成することはできないか調べてみたところ方法があったので備忘録として残しておく。
起きた問題とやりたいこと
レコードの更新(一度作成したレコードのデータをユーザーが編集した場合など)にPUT
を使っていたが、DBに存在しないレコードをPUT
で送ろうとしたところ、404
エラーが返ってきた。通常はPOST
でレコードで作成するようにしているが、PUT
でもレコードの作成ができるようにしたい。
もう一度、説明すると想定している挙動は次の通り。
[ こうなってほしい ]
- 通常は
POST
でレコードを新規作成して、PUT
かPATCH
(部分更新)でレコードの更新 -
PUT
で更新しようとしたレコードがDBに存在しない場合、404エラーにならずに新規作成される
POSTとかPUT、PATCHの違いがよくわからないという場合はPUT か POST か PATCH か?を参照
解決法
公式チュートリアルのPUT as createに解決法が載ってた。
Prior to version 3.0 the REST framework mixins treated PUT as either an update or a create operation, depending on if the object already existed or not.
Allowing PUT as create operations is problematic, as it necessarily exposes information about the existence or non-existence of objects. It's also not obvious that transparently allowing re-creating of previously deleted instances is necessarily a better default behavior than simply returning 404 responses.
Both styles "PUT as 404" and "PUT as create" can be valid in different circumstances, but from version 3.0 onwards we now use 404 behavior as the default, due to it being simpler and more obvious.
If you need to generic PUT-as-create behavior you may want to include something like this AllowPUTAsCreateMixin class as a mixin to your views.
要は、「DRFのバージョン3.0以上ではPUT
で存在しないレコードを更新しようとすると404
ステータスが返ってくるようになってるけど、AllowPUTAsCreateMixinを使えばPUT
でもPOST
のようにレコードを新規作成できるようになるよ」ということのよう。
上記リンク先のスニペットと同じものだが、必要なモジュールのインポート文が抜けていたので足したものを載せておく。これをインポートしてレコード更新に使っているViewクラスにMixinすればPUT
でもレコード作成ができるようになる。フロントエンドで条件分岐でPOST
メソッドとPUT
メソッドを使い分けている場合などに、PUT
のメソッドだけで作成と更新の両方を済ませられるので、コードが簡潔になりそう
from django.http import Http404
from rest_framework import status
from rest_framework.response import Response
from rest_framework.request import clone_request
class AllowPUTAsCreateMixin(object):
"""
The following mixin class may be used in order to support PUT-as-create
behavior for incoming requests.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object_or_none()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
if instance is None:
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
lookup_value = self.kwargs[lookup_url_kwarg]
extra_kwargs = {self.lookup_field: lookup_value}
serializer.save(**extra_kwargs)
return Response(serializer.data, status=status.HTTP_201_CREATED)
serializer.save()
return Response(serializer.data)
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
def get_object_or_none(self):
try:
return self.get_object()
except Http404:
if self.request.method == 'PUT':
# For PUT-as-create operation, we need to ensure that we have
# relevant permissions, as if this was a POST request. This
# will either raise a PermissionDenied exception, or simply
# return None.
self.check_permissions(clone_request(self.request, 'POST'))
else:
# PATCH requests where the object does not exist should still
# return a 404 response.
raise
Author And Source
この問題について(【DRF】PUTメソッドをPOSTメソッドの代わりに使う), 我々は、より多くの情報をここで見つけました https://qiita.com/_masa_u/items/a7a67a9744aa58ec3eef著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .