Django自定义双参数API端点开发及Swagger适配问题
解决方案
方案一:创建独立APIView端点(推荐,无Model/Serializer依赖)
直接用APIView实现独立端点,完全摆脱ModelViewSet的主键约束,参数类型可控,Swagger也能正常识别。
1. 编写视图类
from django.db import connection from rest_framework.views import APIView from rest_framework.response import Response from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi class CheckLicenseStatusView(APIView): @swagger_auto_schema( manual_parameters=[ openapi.Parameter('agent_id', openapi.IN_QUERY, description="Agent ID", type=openapi.TYPE_INTEGER), openapi.Parameter('license_id', openapi.IN_QUERY, description="License ID", type=openapi.TYPE_INTEGER) ], responses={200: openapi.Response('License有效性', openapi.Schema(type=openapi.TYPE_BOOLEAN))} ) def get(self, request): # 获取并验证参数 agent_id = request.query_params.get('agent_id') license_id = request.query_params.get('license_id') if not (agent_id and agent_id.isdigit() and license_id and license_id.isdigit()): return Response({"error": "agent_id和license_id必须为整数"}, status=400) agent_id = int(agent_id) license_id = int(license_id) # 执行自定义SQL查询 with connection.cursor() as cursor: cursor.execute(""" SELECT EXISTS( SELECT 1 FROM agent_license WHERE agent_id = %s AND license_id = %s AND is_active = TRUE ) """, [agent_id, license_id]) result = cursor.fetchone()[0] return Response(result)
2. 注册路由
在项目的urls.py中添加:
from django.urls import path from .views import CheckLicenseStatusView urlpatterns = [ # 其他路由... path('check-license-status/', CheckLicenseStatusView.as_view(), name='check-license-status'), ]
方案二:修复ModelViewSet中的@action问题
如果要在原有AgentLicenseViewSet中实现,需解决主键强制要求和参数类型问题:
1. 修改ViewSet中的@action
from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi from rest_framework.decorators import action from django.db import connection from rest_framework import viewsets class AgentLicenseViewSet(viewsets.ModelViewSet): # 原有ModelViewSet配置(queryset、serializer_class等)... @swagger_auto_schema( manual_parameters=[ openapi.Parameter('agent_id', openapi.IN_PATH, description="Agent ID", type=openapi.TYPE_INTEGER), openapi.Parameter('license_id', openapi.IN_PATH, description="License ID", type=openapi.TYPE_INTEGER) ], responses={200: openapi.Response('License有效性', openapi.Schema(type=openapi.TYPE_BOOLEAN))} ) @action(detail=False, methods=['get'], url_path='check-status/(?P<agent_id>\\d+)/(?P<license_id>\\d+)') def check_status(self, request, agent_id, license_id): # 参数已被Django自动转换为整数 with connection.cursor() as cursor: cursor.execute(""" SELECT EXISTS( SELECT 1 FROM agent_license WHERE agent_id = %s AND license_id = %s AND is_active = TRUE ) """, [agent_id, license_id]) result = cursor.fetchone()[0] return Response(result)
关键修复点
detail=False:声明该action不需要绑定到单个Model实例,路由不会强制要求传入agent_license的主键url_path中用正则(?P<agent_id>\\d+):指定参数必须为整数,Django会自动解析为int类型@swagger_auto_schema:明确参数类型和位置,确保Swagger正确显示
断点未触发的排查
如果用方案二后断点仍不触发,检查:
- 请求的路由是否匹配(比如是否是
/agent-license/check-status/123/456/) - 确认
detail=False是否正确设置(如果设为True,路由会带<pk>,未传pk会导致404,无法进入方法)
内容的提问来源于stack exchange,提问作者jb62
相关产品推荐
相关产品推荐

