ViewSet called on detail delete handler on an action matched url with no delete allowed #9146
-
Not sure if this is reported before # views.py
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from django.http import HttpResponse
class Example(ViewSet):
queryset = None
def retrieve(self, request, pk):
return HttpResponse(b"retrieve")
def delete(self, request, pk):
return HttpResponse(b"delete")
@action(detail=True, methods=["post"])
def custom(self, request, pk):
return HttpResponse(b"custom") # urls.py
from rest_framework import routers
from main.views import Example
router = routers.SimpleRouter(trailing_slash=False)
router.register(r'example', Example, basename="example")
urlpatterns = router.urls
Expected 405 method not allowed |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
I could send a PR if you interest in this fix --- views.py
+++ views.patch.py
@@ -479,6 +479,23 @@
request.force_plaintext_errors(use_plaintext_traceback)
raise exc
+ def get_action_handler_name(self, request):
+ # exit early if `detail` has not been provided
+ if self.detail is None:
+ return None
+
+ # filter for the relevant extra actions
+ actions = [
+ action for action in self.get_extra_actions()
+ if action.detail == self.detail
+ ]
+
+ for action in actions:
+ url_name = '%s-%s' % (self.basename, action.url_name)
+ if url_name == request.resolver_match.url_name and request.method.lower() in action.mapping:
+ return action.mapping[request.method.lower()]
+ return None
+
# Note: Views are made CSRF exempt from within `as_view` as to prevent
# accidental removal of this exemption in cases where `dispatch` needs to
# be overridden.
@@ -497,7 +514,11 @@
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
- if request.method.lower() in self.http_method_names:
+ # action
+ if "name" in request.resolver_match.func.initkwargs:
+ action_name = self.get_action_handler_name(request)
+ handler = getattr(self, action_name) if action_name else self.http_method_not_allowed
+ elif request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else: |
Beta Was this translation helpful? Give feedback.
-
This has to do with your use of the |
Beta Was this translation helpful? Give feedback.
-
@kevin-brown but I think it's still an issue when requested url is |
Beta Was this translation helpful? Give feedback.
Are you saying the
destroy
method (if defined instead ofdelete
on your viewset) is being triggered upon aDELETE
to a custom detail endpoint?Right now if you keep it as the
delete
method (which is not supported by DRF, that's not an expected ViewSet method) then that method will always be triggered for anyDELETE
requests on your ViewSet. That's actually why it's not supported or documented, since the expectation is that thedestroy
method will be defined instead.