代码之家  ›  专栏  ›  技术社区  ›  James Lin

Django Rest框架中的action decorator方法需要在类http_method_names中指定

  •  0
  • James Lin  · 技术社区  · 3 年前

    DRF版本是3.11.2

    我正在编写一些现有代码,向视图集中添加一个额外的“删除”操作,但我得到了 405 Method not allowed 考虑下面的例子

    class UserViewSet(ModelViewSet):
        ....
        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方法不允许 然而,如果我加上 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()
            ....
    
    

    但这并不理想,因为我不想允许对用户执行“删除”操作,同时我可以覆盖 删去 / destroy 要避免用户在viewset上被删除,此方法非常优雅。

    所以问题是,这是一个bug还是设计的?所谓设计,我指的是由 @action 假设正在处理在中定义的相同模型 ModelViewSet (在这种情况下是用户,而不是个人资料)?

    0 回复  |  直到 3 年前
        1
  •  1
  •   LiquidDeath    3 年前

    问题在于设置 http_method_names 属性设置为ModelViewSet。既然你把它设为 get post ,其他方法( put , patch , delete )不会在课堂上工作。要么你必须添加 删去 方法 http_方法_名称 属性或移除整个属性来修复此问题,如下所示。

    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)
    

    如果你不想要别的方法 收到 , 邮递 , 删去 为什么不使用mixins?

    更新: 如果不想让delete方法在主视图集上工作,只需覆盖它,如图所示。

     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)