Django REST framework: PUT method not allowed in ViewSet with def () update

In DRF, I have a simple ViewSet similar to this:

class MyViewSet(viewsets.ViewSet): def update(self, request): # do things... return Response(status=status.HTTP_200_OK) 

When I try to execute a PUT request, I get an error as the PUT method is not allowed. If I use def put(self, request): everything will work fine. According to docs, I should use def update(): not def put(): why is this happening?

+6
source share
3 answers

This is because APIView does not have a handler defined for the .put() method, so the incoming request cannot be matched to the handler method in the view, thereby throwing an exception.

(Note: viewsets.ViewSet inherit from ViewSetMixin and APIView )

The dispatch() method in APIView checks if a method handler is defined for a method request. If the dispatch() method finds a handler for the request method, it returns an appropriate response. Otherwise, a MethodNotAllowed exception is MethodNotAllowed .

According to the source code of the dispatch() method in the APIView class:

 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 

Since the handler for the .put() method is not defined in your view, DRF calls the standby handler .http_method_not_allowed . This raises a MethodNotAllowed exception.

Source code for .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 

Why did this work when you defined .put() in your view?

When you define def put(self, request): in your view, DRF can map the incoming request method to the handler method in the view. This led to the return of the corresponding response without exception.

+2
source

If there is a similar problem with this code with the "PUT not allowed" method, because the request did not contain "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) 

It turned out that I missed the 'id' in the serializer fields, so the PUT request could not provide the record identifier. The fixed version of the serializer is below:

 class ProfileStep2Serializer(serializers.ModelSerializer): class Meta: model = Profile fields = ('id', 'middle_initial', 'mobile_phone', 'address', 'apt_unit_num', 'city', 'state', 'zip') 
+7
source

Sometimes it is different for POST and PUT, because PUT uses the id in the URL. In this case, yoy'll get this error: "PUT is not allowed."

Example:

  • POST: /api/users/
  • PUT: /api/users/1/

Hope this saves a lot of time for someone.

+4
source

All Articles