flo*_*urr 13 python django-rest-framework
在DRF中,我有一个像这样的简单ViewSet:
class MyViewSet(viewsets.ViewSet):
def update(self, request):
# do things...
return Response(status=status.HTTP_200_OK)
Run Code Online (Sandbox Code Playgroud)
当我尝试PUT请求时,我得到一个错误,如方法PUT不允许.如果我使用def put(self, request):所有的东西工作正常.因此到的文档,我应该使用def update():没有def put():,为什么会发生?
yes*_*ema 38
有时它对于POST和PUT是不同的,因为PUT在URL中使用id 在这种情况下,yoy会得到这个错误:" PUT不允许 ".
例:
/api/users//api/users/1/希望它能为某人节省大量时间
此代码有类似的"方法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)
Run Code Online (Sandbox Code Playgroud)
原来我在序列化器字段中错过了'id',因此PUT请求无法为记录提供id.序列化器的固定版本如下:
class ProfileStep2Serializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('id', 'middle_initial', 'mobile_phone', 'address', 'apt_unit_num', 'city', 'state', 'zip')
Run Code Online (Sandbox Code Playgroud)
这个答案是正确的,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
Run Code Online (Sandbox Code Playgroud)
这是因为APIView没有为.put()方法定义处理程序,因此传入的请求无法映射到视图上的处理程序方法,从而引发异常。
(注:viewsets.ViewSet继承自ViewSetMixin和APIView)
中的dispatch()方法APIView检查是否为请求定义了方法处理程序method。如果该dispatch()方法找到请求方法的处理程序,则返回适当的响应。否则,它会引发异常MethodNotAllowed。
根据类中dispatch()方法的源代码APIView:
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
Run Code Online (Sandbox Code Playgroud)
由于.put()方法处理程序未在您的视图中定义,DRF 调用回退处理程序.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
Run Code Online (Sandbox Code Playgroud)
当您.put()在视图中定义时,为什么它有效?
当您def put(self, request):在视图中定义时,DRF 可以将传入的请求方法映射到视图上的处理程序方法。这导致返回适当的响应,而不会引发异常。