Метод Django Rest Framework в декораторе действий должен быть указан в классе http_method_names
ВерсияDRF - 3.11.2
Я работал над существующим кодом, чтобы добавить дополнительное действие "delete" к набору представлений, но у меня получилось 405 Method not allowed, рассмотрим следующий выдуманный пример
class UserViewSet(ViewSet):
....
queryset = User.objects.all()
http_method_names = ['get', 'post']
@action(detail=True, method=['delete'])
def delete_profile(self, request, pk=None)
Profile.objects.get(user=pk).delete()
....
Как я уже сказал, когда я делаю вызов метода delete в /user/123/delete_profile, я получаю 405 Method not allowed, однако, если я добавляю delete к http_method_names, как показано ниже, все работает нормально.
class UserViewSet(ViewSet):
....
queryset = User.objects.all()
http_method_names = ['get', 'post', 'delete']
@action(detail=True, method=['delete'])
def delete_profile(self, request, pk=None)
Profile.objects.get(user=pk).delete()
....
Но это не идеально, поскольку я не хочу разрешить операцию "удаления" пользователя, хотя я могу переписать метод delete в наборе представлений, чтобы избежать удаления пользователя, но это не очень элегантно.
Итак, вопрос в том, является ли это ошибкой или замыслом?
Проблема заключается в установке атрибута http_method_names для ModelViewSet. Поскольку вы установили его только на get и post, другие методы (put, patch, delete) не будут работать с классом. Чтобы исправить это, вам нужно либо добавить метод delete к атрибуту http_method_names, либо удалить весь атрибут, как показано ниже.
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
@action(detail=True, methods=['delete'])
def delete_profile(self, request, pk=None):
Profile.objects.get(user=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Также, если вы не хотите, чтобы работали другие методы, кроме get, post, delete, почему бы не использовать миксины?
Update : если вы не хотите, чтобы метод удаления работал на главном наборе представлений, просто переопределите его, как показано на рисунке.
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
queryset = User.objects.all()
@action(detail=True, methods=['delete'])
def delete_profile(self, request, pk=None):
....
def destroy(self, request, *args, **kwargs):
return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED)