You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF中@action装饰接口提示GET方法不允许且多方法失效问题

DRF ViewSet中@action路由冲突导致请求方法失效的解决

问题现象

在基于Django REST Framework的项目中,通过ArticleAPI视图集的@action装饰器定义了多个处理Comment模型的接口,但测试时所有请求都返回{"detail": "Method \"GET\" not allowed."},POST、PATCH、DELETE等方法也无法正常工作。查看生成的路由发现,所有评论相关接口都指向同一个URL:

<URLPattern '^articles/(?P<pk>[^/.]+)/comments/$' [name='articles-article-create-comment']>, 
<URLPattern '^articles/(?P<pk>[^/.]+)/comments/$' [name='articles-article-update-comment']>, 
<URLPattern '^articles/(?P<pk>[^/.]+)/comments/$' [name='articles-article-comments-object']>, 
<URLPattern '^articles/(?P<pk>[^/.]+)/comments/$' [name='articles-article-comments-list']>, 
<URLPattern '^articles/(?P<pk>[^/.]+)/comments/$' [name='articles-article-update-comment']>

核心原因

  1. 路由URL重复:所有@action的url_path都设置为'comments',DRF在注册路由时会覆盖之前的同名URL,最终只有最后一个注册的路由生效,导致其他方法无法匹配。
  2. 单个评论接口缺少参数:获取单个评论的方法未在URL中定义评论的pk参数,无法定位到具体评论实例。
  3. 视图方法逻辑错误:创建、更新、删除评论的方法中,错误调用了视图集针对Article的create/partial_update/perform_destroy方法,而非操作Comment实例。

解决方案

1. 调整路由结构,区分列表与单个评论接口

修改@action的url_path,为单个评论接口添加评论pk的URL参数:

  • 评论列表(GET/POST):保持url_path='comments'
  • 单个评论(GET/PATCH/DELETE):设置url_path='comments/(?P<comment_pk>[^/.]+)'

2. 修正视图方法逻辑

以下是修正后的ArticleAPI关键代码:

class ArticleAPI(viewsets.ModelViewSet):
    serializer_class = ArticleSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    queryset = Article.objects.order_by('number')
    lookup_field = 'pk'

    # 获取文章的所有评论(列表)
    @action(methods=['GET'], detail=True, url_path='comments', url_name='article-comments-list')
    def get_comments_list(self, request, pk=None):
        article = self.get_object()
        serializer = CommentSerializer(article.comment_set.all(), many=True)
        return Response(serializer.data)

    # 获取单条评论
    @action(methods=['GET'], detail=True, url_path='comments/(?P<comment_pk>[^/.]+)', url_name='article-comment-detail')
    def get_comment_detail(self, request, pk=None, comment_pk=None):
        article = self.get_object()
        comment = article.comment_set.get(pk=comment_pk)
        serializer = CommentSerializer(comment)
        return Response(serializer.data)

    # 创建评论
    @action(methods=['POST'], detail=True, url_path='comments', url_name='article-create-comment')
    def create_comment(self, request, pk=None):
        article = self.get_object()
        serializer = CommentSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 关联当前文章和登录用户
        serializer.save(article=article, author=request.user)
        return Response({"comment": serializer.data}, status=201)

    # 更新评论
    @action(methods=['PATCH'], detail=True, url_path='comments/(?P<comment_pk>[^/.]+)', url_name='article-update-comment')
    def partial_update_comment(self, request, pk=None, comment_pk=None):
        article = self.get_object()
        comment = article.comment_set.get(pk=comment_pk)
        
        # 检查权限(确保是评论作者或管理员)
        if not (request.user == comment.author or request.user.is_staff):
            return Response({"errors": "无权限修改此评论"}, status=403)
        
        serializer = CommentSerializer(comment, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({"comment": serializer.data})

    # 删除评论
    @action(methods=['DELETE'], detail=True, url_path='comments/(?P<comment_pk>[^/.]+)', url_name='article-delete-comment')
    def delete_comment(self, request, pk=None, comment_pk=None):
        article = self.get_object()
        comment = article.comment_set.get(pk=comment_pk)
        
        if not (request.user == comment.author or request.user.is_staff):
            return Response({"errors": "无权限删除此评论"}, status=403)
        
        comment.delete()
        return Response(status=204)

3. 验证路由

修正后生成的路由会区分不同的URL:

  • 评论列表:^articles/(?P<pk>[^/.]+)/comments/$(支持GET/POST)
  • 单个评论:^articles/(?P<pk>[^/.]+)/comments/(?P<comment_pk>[^/.]+)/$(支持GET/PATCH/DELETE)

此时再通过Postman测试各方法,即可正常响应。

内容的提问来源于stack exchange,提问作者Sanyokk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 21:30:53