Метод 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)
Вернуться на верх