在DRF中,我有一个像这样的简单ViewSet:
class MyViewSet(viewsets.ViewSet):
def update(self, request):
# do things...
return Response(status=status.HTTP_200_OK)
当我尝试PUT请求时,我得到一个错误,如方法PUT不允许。如果我使用def put(self, request):
,一切正常。根据{{3}}我应该使用def update():
而不是def put():
,为什么会这样?
答案 0 :(得分:29)
有时 POST和PUT不同,因为 PUT在网址中使用id 在这种情况下,yoy会收到此错误:“ PUT不允许”。
示例:
/api/users/
/api/users/1/
希望它能为某人节省大量时间
答案 1 :(得分:7)
此代码存在类似的“方法PUT不允许”问题,因为请求中缺少“id”:
class ProfileStep2Serializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('middle_initial', 'mobile_phone', 'address', 'apt_unit_num', 'city', 'state', 'zip')
class Step2ViewSet(viewsets.ModelViewSet):
serializer_class = ProfileStep2Serializer
def get_queryset(self):
return Profile.objects.filter(pk=self.request.user.profile.id)
原来我在序列化器字段中错过了'id',因此PUT请求无法为记录提供id。序列化器的固定版本如下:
class ProfileStep2Serializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('id', 'middle_initial', 'mobile_phone', 'address', 'apt_unit_num', 'city', 'state', 'zip')
答案 2 :(得分:2)
这是因为FBSDKShareOpenGraphContent
没有为Clipboard.SetText(Label1.Content+ Label2.Content+ Label3.Content+ Label4.Content+ Label5.Content+ Label6.Content+ Label7.Content)
方法定义处理程序,因此传入的请求无法映射到视图上的处理程序方法,从而引发异常。
(注意:APIView
继承自.put()
和viewsets.ViewSet
)
ViewSetMixin
中的APIView
方法检查是否为请求dispatch()
定义了方法处理程序。如果APIView
方法找到请求方法的处理程序,则返回适当的响应。否则,它会引发异常MethodNotAllowed
。
根据method
类中dispatch()
方法的源代码:
dispatch()
由于您的视图中未定义APIView
方法处理程序,因此DRF会调用回退处理程序def dispatch(self, request, *args, **kwargs):
...
...
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
# here handler is fetched for the request method
# `http_method_not_allowed` handler is assigned if no handler was found
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs) # handler is called here
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
。这会引发.put()
例外。
.http_method_not_allowed
的源代码是:
MethodNotAllowed
为什么在您的视图中定义.http_method_not_allowed()
后它才有效?
在视图中定义def http_method_not_allowed(self, request, *args, **kwargs):
"""
If `request.method` does not correspond to a handler method,
determine what kind of exception to raise.
"""
raise exceptions.MethodNotAllowed(request.method) # raise an exception
时,DRF可以将传入的请求方法映射到视图上的处理程序方法。这导致返回适当的响应而不会引发异常。
答案 3 :(得分:1)
这个答案是正确的,Django REST framework: method PUT not allowed in ViewSet with def update(),PUT是不允许的,因为DRF希望实例id在URL中。话虽这么说,在你的ViewSet中使用这个mixin可能是解决它的最好方法(从下面的https://gist.github.com/tomchristie/a2ace4577eff2c603b1b复制粘贴)
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
答案 4 :(得分:0)
def update(self, request, pk=None):
data_in = request.data
print(data_in)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=False)
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()
data_out = serializer.data
return Response(serializer.data)
答案 5 :(得分:0)
使用 Django 视图集,您可以轻松地映射 url 中的方法,例如
path('createtoken/', CreateTokenView.as_view({'post': 'create', 'put':'update'}))
然后在您的类中根据需要覆盖方法:
class CreateTokenView(viewsets.ModelViewSet):
queryset = yourSet.objects.all()
serializer_class = yourSerializer
def create(self, request, *args, **kwargs):
#any method you want here
return Response("response")
def update(self, request, *args, **kwargs):
# any method you want here
return Response("response")