Django DRF创建API报错:get_empinfo()收到意外参数'pk'
问题分析与解决方案
错误原因
你遇到的TypeError: EmployeeInfoViewset.get_empinfo() got an unexpected keyword argument 'pk'核心问题有两个:
- 类方法与普通视图函数混淆:你把
@api_view装饰的普通视图函数定义在了EmployeeInfoViewset类内部,但类的实例方法第一个参数是self,而@api_view期望的是第一个参数为request的普通函数。直接通过EmployeeInfoViewset.get_empinfo调用时,参数传递逻辑完全混乱,导致路由匹配时传入的参数不匹配。 - ViewSet使用方式错误:
ViewSet是DRF用于批量生成标准CRUD路由的工具,你手动绑定类方法的方式不符合其设计规范,引发路由参数冲突。
修复方案
方案一:改为独立视图函数(简单直接)
将视图函数从类中移出,作为独立的API视图使用:
修改views.py
from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from django.db import connection from django.http import JsonResponse from .models import EmpPersonalInfo from .serializers import EmpInfoSerializer @api_view(['GET']) def get_empinfo(request, emp_id=None): with connection.cursor() as cursor: if emp_id is not None: cursor.execute("CALL sp_get_empInfo(%s)", [emp_id]) else: cursor.execute("CALL sp_get_empInfo('')") results = cursor.fetchall() employee_info = [] for result in results: employee_info.append({ 'emp_id': result[0], 'dob': result[1], 'mobile': result[2], 'email': result[3], 'aadhar': result[4], 'pan': result[5], 'address1': result[6], 'city': result[7], 'state': result[8], 'pincode': result[9] }) return JsonResponse(employee_info, safe=False) @api_view(['POST']) def add_empinfo(request): serializer = EmpInfoSerializer(data=request.data) if serializer.is_valid(): emp_id = serializer.validated_data.get('emp_id') dob = serializer.validated_data.get('dob') mobile = serializer.validated_data.get('mobile') email = serializer.validated_data.get('email') aadhar = serializer.validated_data.get('aadhar') pan = serializer.validated_data.get('pan') add1 = serializer.validated_data.get('add1') city = serializer.validated_data.get('city') state = serializer.validated_data.get('state') pincode = serializer.validated_data.get('pincode') with connection.cursor() as cursor: cursor.callproc('sp_add_empInfo', [ emp_id, dob, mobile, email, aadhar, pan, add1, city, state, pincode ]) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # 若不需要ViewSet,可直接删除该类 class EmployeeInfoViewset(viewsets.ViewSet): queryset = EmpPersonalInfo.objects.all() serializer_class = EmpInfoSerializer lookup_field = 'emp_id'
修改urls.py
from django.urls import path from .views import get_empinfo, add_empinfo urlpatterns = [ path('empinfo', get_empinfo, name='empinfo-list'), path('empinfo/<int:emp_id>', get_empinfo, name='empinfo-detail'), path('empinfo/add', add_empinfo, name='add_empinfo'), ]
方案二:使用ViewSet标准方法(符合DRF规范)
如果想保留ViewSet的特性,重写其内置的list、retrieve、create方法:
修改views.py
from rest_framework import viewsets from rest_framework.response import Response from rest_framework import status from django.db import connection from .models import EmpPersonalInfo from .serializers import EmpInfoSerializer class EmployeeInfoViewset(viewsets.ViewSet): lookup_field = 'emp_id' # 获取所有员工信息 def list(self, request): with connection.cursor() as cursor: cursor.execute("CALL sp_get_empInfo('')") results = cursor.fetchall() employee_info = [] for result in results: employee_info.append({ 'emp_id': result[0], 'dob': result[1], 'mobile': result[2], 'email': result[3], 'aadhar': result[4], 'pan': result[5], 'address1': result[6], 'city': result[7], 'state': result[8], 'pincode': result[9] }) return Response(employee_info) # 获取单个员工信息 def retrieve(self, request, emp_id=None): with connection.cursor() as cursor: cursor.execute("CALL sp_get_empInfo(%s)", [emp_id]) results = cursor.fetchall() if not results: return Response({"error": "员工不存在"}, status=status.HTTP_404_NOT_FOUND) employee_info = { 'emp_id': results[0][0], 'dob': results[0][1], 'mobile': results[0][2], 'email': results[0][3], 'aadhar': results[0][4], 'pan': results[0][5], 'address1': results[0][6], 'city': results[0][7], 'state': results[0][8], 'pincode': results[0][9] } return Response(employee_info) # 新增员工信息 def create(self, request): serializer = EmpInfoSerializer(data=request.data) if serializer.is_valid(): emp_id = serializer.validated_data.get('emp_id') dob = serializer.validated_data.get('dob') mobile = serializer.validated_data.get('mobile') email = serializer.validated_data.get('email') aadhar = serializer.validated_data.get('aadhar') pan = serializer.validated_data.get('pan') add1 = serializer.validated_data.get('add1') city = serializer.validated_data.get('city') state = serializer.validated_data.get('state') pincode = serializer.validated_data.get('pincode') with connection.cursor() as cursor: cursor.callproc('sp_add_empInfo', [ emp_id, dob, mobile, email, aadhar, pan, add1, city, state, pincode ]) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
修改urls.py
使用DRF路由器自动生成标准路由,若需要保留/empinfo/add路径可额外添加:
from django.urls import path, include from rest_framework.routers import DefaultRouter from .views import EmployeeInfoViewset router = DefaultRouter() router.register(r'empinfo', EmployeeInfoViewset, basename='empinfo') urlpatterns = [ path('', include(router.urls)), # 保留自定义的add路径 path('empinfo/add', EmployeeInfoViewset.as_view({'post': 'create'}), name='add_empinfo'), ]
自动生成的标准路由:
GET /empinfo/:获取所有员工信息GET /empinfo/{emp_id}/:获取单个员工信息POST /empinfo/:新增员工信息
额外注意事项
- 你的
EmpPersonalInfo模型设置了managed = False,需确保存储过程与数据库表结构完全匹配。 - 确认
EmpInfoSerializer的字段与模型、存储过程参数一致,特别是emp_id作为OneToOne主键的序列化配置。
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

