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

使用Django REST Framework API Key时POST方法不允许的问题

问题分析与解决方案

核心问题

  1. create方法未正确嵌入ViewSet类:你的create函数定义在ChequeViewset类外部,导致DRF无法识别这个自定义的POST请求处理逻辑,最终返回"Method not allowed"。
  2. 路由配置存在冗余重复(非直接诱因,但可优化)。

修复步骤

1. 将create方法移至ChequeViewset类内部

把自定义的create方法调整缩进,放入ChequeViewset类中,确保DRF的ModelViewSet能正确绑定POST请求到该方法:

class ChequeViewset(viewsets.ModelViewSet):
    queryset = Cheque.objects.all()
    serializer_class = ChequeUpdateSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['cheque_number', 'sequence_number', 'status', 'todo']

    serializers_permission_by_action = {
        'list': (ChequeSerializer, []),
        'retrieve': (ChequeSerializer, []),
        'create': (ChequeCreateSerializer, []),
        'update': (ChequeUpdateSerializer, []),
        'partial_update': (ChequePatchSerializer, []),
        'destroy': (ChequePatchSerializer, []),
    }

    # 修正:将create方法移至类内部
    def create(self, request, *args, **kwargs):
        """
        create method used by BOT need to expose this api 
        with different authntication
        """
        try:
            serializer = self.get_serializer(data=request.data)
            if not serializer.is_valid():
                return Response(
                    {"status": "fail", "message": serializer.errors},
                    status=status.HTTP_400_BAD_REQUEST
                )

            validated_data = serializer.validated_data
            session_object = validated_data.pop('session', None)
            session_id = session_object.id if session_object else None
            if not session_id:
                return Response(
                    {"status": "fail", "message": "Session object not found."},
                    status=status.HTTP_400_BAD_REQUEST
                )
            result = process_cheque_task.delay(
                validated_data=validated_data, 
                pdf=request.FILES['file'].read(), 
                session_id=session_id,
                )
            return Response(
                {"status": "success", "message": "Cheque information sent to processing queue."},
                status=status.HTTP_201_CREATED
            )
        except Exception as e:
            print(e)
            return Response(
                {"status": "error", "message": "An error occurred during cheque creation."},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    def get_permissions(self):
        """
        Override the default permissions for the view.
        """
        try:
            if 'bot' in self.request.path:
                return [HasAPIKey()]
            # Return the custom permission classes for the current action.
            return [permission() for permission in self.serializers_permission_by_action[self.action][1]]
        except KeyError:
            # If the current action is not found in serializers_permission_by_action,
            # default to using the standard permissions.
            return super().get_permissions()

2. 优化路由配置(可选但推荐)

避免重复注册同一个ViewSet到两个router,简化配置逻辑:

# urls.py
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register('cheque', ChequeViewset, basename='cheque')

urlpatterns = [
    path('', include(router.urls)),
    # 直接绑定bot路径的指定action,避免router重复注册
    path('bot/cheque/', ChequeViewset.as_view({'get': 'list', 'post': 'create'}), name='bot-cheque'),
]

或者保留双router模式,但调整注册路径避免冲突:

router_with_bot = DefaultRouter()
router_with_bot.register('cheque', ChequeViewset, basename='bot-cheque')

router = DefaultRouter()
router.register('cheque', ChequeViewset, basename='cheque')

urlpatterns = [
    path('', include(router.urls)),
    path('bot/', include(router_with_bot.urls)),
]

此时bot端点的POST请求路径为/bot/cheque/,避免与根路径端点冲突。

3. 验证HasAPIKey权限类的正确性

确保权限类正确实现了API Key校验逻辑:

from rest_framework.permissions import BasePermission

class HasAPIKey(BasePermission):
    def has_permission(self, request, view):
        api_key = request.headers.get('X-Api-Key')
        # 替换为你的实际校验逻辑(如从数据库查询合法Key)
        return api_key == 'YOtxWIRR.OGgGvTaND1OEKJYvDtLAmBnR8tFFFTxz'

验证修复

  1. 启动服务后,向/bot/cheque/(或你配置的bot路径)发送POST请求,携带正确的X-Api-Key头和请求数据;
  2. 检查是否返回201 Created状态及预期响应内容;
  3. 未携带合法API Key时,应返回403 Forbidden,确认权限控制生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 10:05:21