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)
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.