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

Django DRF创建API报错:get_empinfo()收到意外参数'pk'

问题分析与解决方案

错误原因

你遇到的TypeError: EmployeeInfoViewset.get_empinfo() got an unexpected keyword argument 'pk'核心问题有两个:

  1. 类方法与普通视图函数混淆:你把@api_view装饰的普通视图函数定义在了EmployeeInfoViewset类内部,但类的实例方法第一个参数是self,而@api_view期望的是第一个参数为request的普通函数。直接通过EmployeeInfoViewset.get_empinfo调用时,参数传递逻辑完全混乱,导致路由匹配时传入的参数不匹配。
  2. 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/:新增员工信息

额外注意事项

  1. 你的EmpPersonalInfo模型设置了managed = False,需确保存储过程与数据库表结构完全匹配。
  2. 确认EmpInfoSerializer的字段与模型、存储过程参数一致,特别是emp_id作为OneToOne主键的序列化配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 23:54:58