Python Django REST framework:在具有def update()的ViewSet中不允许使用方法PUT
在DRF中,我有一个简单的视图集,如下所示:Python Django REST framework:在具有def update()的ViewSet中不允许使用方法PUT,python,django-rest-framework,Python,Django Rest Framework,在DRF中,我有一个简单的视图集,如下所示: class MyViewSet(viewsets.ViewSet): def update(self, request): # do things... return Response(status=status.HTTP_200_OK) 当我尝试一个PUT请求时,我得到了一个错误,比如方法PUT not allowed。如果我使用def put(self,request):一切正常。因此,我
class MyViewSet(viewsets.ViewSet):
def update(self, request):
# do things...
return Response(status=status.HTTP_200_OK)
当我尝试一个PUT请求时,我得到了一个错误,比如方法PUT not allowed。如果我使用
def put(self,request):
一切正常。因此,我应该使用def update():
而不是def put():
,为什么会发生这种情况?这是因为APIView
没有为.put()
方法定义处理程序,因此传入的请求无法映射到视图上的处理程序方法,从而引发异常。
(注意:viewsets.ViewSet
继承自ViewSetMixin
和apieview
)
APIView
中的dispatch()
方法检查是否为请求方法定义了方法处理程序。如果dispatch()
方法找到请求方法的处理程序,它将返回相应的响应。否则,它将引发一个异常
根据APIView
类中dispatch()
方法的源代码:
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()
方法处理程序,因此DRF调用回退处理程序.http\u method\u not\u allowed
。这会引发方法不允许的异常
.http\u method\u not\u 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
当您在视图中定义.put()
时,它为什么起作用?
在视图中定义defput(self,request):
时,DRF可以将传入的请求方法映射到视图上的处理程序方法。这导致在没有引发异常的情况下返回相应的响应。此代码存在类似的“不允许方法放置”问题,因为请求中缺少“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')
将需求id
放入URL
有时POST和PUT之间存在差异,因为PUT需要id
在URL中
这就是为什么会出现错误:“不允许放置”
例如:
- POST:
/api/users/
- PUT:
/api/users/1/
希望它能为某人节省大量时间这个答案是正确的,不允许使用PUT,因为DRF希望实例id位于URL中。也就是说,在视图集中使用此mixin可能是修复它的最佳方法(从下面粘贴的副本)
使用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")
因此,如果我想使用create,我只需要映射它?在您的视图中定义update()
时,您是否在URL中定义了router
。请检查您是否按照文档中的说明正确定义了视图集
和路由器
,因为路由器
本身将放置
功能设置为指向更新
功能。因此,每当PUT
请求到来时,处理程序将执行.update()
操作的代码。您调用的URL是否包含详细的“pk”路径参数?原因调用根资源的PUT,例如/users/without/users/将导致不允许使用方法。请注意,如果您只定义方法PUT
(而不是通过DRF mixinupdate
),那么它将在没有ID的情况下工作。当然,但不是一直都可以;设想一个“单例”资源,没有ID。如果您有一个代表当前登录用户的/user/me
端点,这可能是一个常见的用例。确实节省了很多时间。谢谢你在我的例子中,这很有魅力,因为我使用了一个viewset.ModelViewSet
和一个与之相关的serializer.ModelSerializer
。你也可以使用PATCH
方法来执行Django模型的部分更新。这个代码片段可以解决这个问题,确实有助于提高你文章的质量。记住,你是在为将来的读者回答这个问题,那些人可能不知道你的代码建议的原因。你真是个好人,你为我节省了很多时间!!
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")