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

Django DRF@action报错:意外关键字参数'id'问题求助

Django REST Framework 订阅功能报错排查

问题现象

调用接口/api/users/11/subscribe/时触发以下错误:

TypeError: set_or_delete_subscribe() got an unexpected keyword argument 'id'
[10/Mar/2025 08:38:23] "POST /api/users/11/subscribe/ HTTP/1.0" 500 88724

相关代码

CustomUserViewSet 实现

class CustomUserViewSet(UserViewSet):
    
    serializer_class = UserSerializer
    pagination_class = PageNumberPagination
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        queryset = User.objects.all()
        return queryset
    
    @action(detail=False, methods=['put', 'delete'], url_path='me/avatar')
    def set_avatar(self, request):
        if request.method == 'PUT':
            serializer = SetAvatarSerializer(
                request.user,
                data=request.data,
                partial=True
            )
            serializer.is_valid(raise_exception=True)
            serializer.save()
            return Response(status=status.HTTP_200_OK)
        user = request.user
        user.avatar.delete()
        user.save()
        return Response(status=status.HTTP_204_NO_CONTENT)
    
    @action(detail=True, methods=['post', 'delete'], url_path='subscribe')
    def set_or_delete_subscribe(self, request, pk=None):
        user = request.user
        user_to_subscribe = self.kwargs['id']
        if request.method == 'POST':
            _, created = Subscription.objects.get_or_create(user=user, subscribed=user_to_subscribe)
            if created:
                return Response(status=status.HTTP_201_CREATED)
            return Response(status=status.HTTP_400_BAD_REQUEST)

        if request.method == 'DELETE':
            subscription = Subscription.objects.filter(user=user, subscribed=user_to_subscribe).delete()
            if subscription:
                return Response(status=status.HTTP_204_NO_CONTENT)
            return Response(status=status.HTTP_400_BAD_REQUEST)

Subscription 模型定义

class Subscription(models.Model):
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='subscriptions'
    )
    subscribed = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='subscribed'
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['user', 'subscribed'], name='unique_subscription')
        ]

URL 路由配置

router = DefaultRouter()
router.register(r'tags', TagViewSet, basename='tags')
router.register(r'recipes', RecipeViewSet, basename='recipes')
router.register(r'ingredients', IngridientsViewSet, basename='ingredients')
router.register(r'users', CustomUserViewSet, basename='users')

问题原因及修复方案

核心问题

  1. 参数签名不匹配:DRF 默认会根据模型主键字段名传递参数(如果User模型主键是id,路由会传递id参数),但你的视图方法签名定义的是pk=None,导致方法无法接收id参数,触发TypeError。
  2. 用户实例获取错误:直接从self.kwargs['id']拿到的是字符串类型的ID值,不能直接传给Subscription模型的subscribed字段(该字段需要User实例)。

修复步骤

步骤1:统一参数与实例获取逻辑

推荐使用DRF内置的get_object()方法获取目标用户,自动处理权限校验和404错误,同时修正方法签名匹配路由参数:

@action(detail=True, methods=['post', 'delete'], url_path='subscribe')
def set_or_delete_subscribe(self, request, id=None):
    user = request.user
    # 用get_object()获取目标用户实例
    user_to_subscribe = self.get_object()

    if request.method == 'POST':
        _, created = Subscription.objects.get_or_create(user=user, subscribed=user_to_subscribe)
        if created:
            return Response(status=status.HTTP_201_CREATED)
        return Response(status=status.HTTP_400_BAD_REQUEST, data={"detail": "已订阅该用户"})

    if request.method == 'DELETE':
        deleted_count, _ = Subscription.objects.filter(user=user, subscribed=user_to_subscribe).delete()
        if deleted_count > 0:
            return Response(status=status.HTTP_204_NO_CONTENT)
        return Response(status=status.HTTP_400_BAD_REQUEST, data={"detail": "未订阅该用户"})

步骤2:优化错误判断

filter().delete()返回的是(删除记录数, 模型类型统计)的元组,需通过判断删除记录数是否大于0来确认操作是否成功,而非直接判断返回值。

验证修复

重启服务后,调用POST /api/users/11/subscribe/可正常创建订阅,DELETE请求可正常取消订阅,不再触发TypeError。


内容的提问来源于stack exchange,提问作者st.splash

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:46:06