使用Django REST Framework API Key时POST方法不允许的问题
问题分析与解决方案
核心问题
create方法未正确嵌入ViewSet类:你的create函数定义在ChequeViewset类外部,导致DRF无法识别这个自定义的POST请求处理逻辑,最终返回"Method not allowed"。- 路由配置存在冗余重复(非直接诱因,但可优化)。
修复步骤
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'
验证修复
- 启动服务后,向
/bot/cheque/(或你配置的bot路径)发送POST请求,携带正确的X-Api-Key头和请求数据; - 检查是否返回
201 Created状态及预期响应内容; - 未携带合法API Key时,应返回
403 Forbidden,确认权限控制生效。
内容的提问来源于stack exchange,提问作者Ragner
相关产品推荐
相关产品推荐

