Django DRF注册报Expected pk value received BoundField错误
Django注册接口序列化报错与403问题修复
问题表现
- 注册流程抛出序列化校验错误:
{'user': [ErrorDetail(string='Incorrect type. Expected pk value, received BoundField.', code='incorrect_type')]} - 注册接口
/api/v1.0/user/register-patient/返回403 Forbidden状态码 - 已确认PatientSerializer可正常将
is_active=False的用户数据写入数据库,报错来源为TokenSerializer
根因分析
接口返回403并非权限配置问题,RegisterView已配置AllowAny权限,403是TokenSerializer校验失败后,代码走到固定错误返回分支导致的,具体错误点有3个:
- 用户ID传值类型错误:构造TokenSerializer入参时写的
patient_serializer['id']拿到的是序列化器的BoundField实例,不是用户主键的整数值,DRF外键字段要求接收pk值(整数ID),类型不匹配直接触发类型错误。 - Token字段名不匹配:
VerificatonToken模型和TokenSerializer中定义的验证令牌字段名为verification_token,但传参时错误使用了token作为key,序列化器无法读取到令牌值,校验直接失败。 - 邮箱验证逻辑隐患:PatientVerificationView中查询验证令牌时,错误使用了不存在的
token字段作为查询条件,且未对查询结果做空判断,后续用户点击验证链接时会出现查询失败、空指针报错的问题。
修复方案
1. 修正注册接口中TokenSerializer的传参逻辑
找到RegisterView类中构造verification_token_serializer的代码块,替换为以下内容:
verification_token_serializer = TokenSerializer( data={ # 通过patient_serializer.data取序列化后的输出字典,拿到整数类型的用户ID 'user': patient_serializer.data['id'], # 字段名和模型/序列化器定义保持一致 'verification_token': verification_token } )
2. 修正邮箱验证接口的查询逻辑
找到PatientVerificationView类的get方法,替换查询逻辑为以下内容,补充空值判断避免报错:
def get(self, request, pk, format=None): print("Verifying Patient", pk) # 使用模型中实际存在的verification_token字段查询,先判断查询结果是否为空 tokenObj = VerificatonToken.objects.filter(verification_token=pk).first() if not tokenObj: return Response('无效的验证链接', status=404) user = User.objects.filter(id=tokenObj.user.id).first() if user: patient_serializer = PatientSerializer( user, data={'is_active': True}, partial=True) if patient_serializer.is_valid(raise_exception=False): patient_serializer.save() return Response('Patient email verified', status=200) return Response(status=404)
注:更新用户时加上
partial=True参数,允许部分字段更新,避免序列化器校验其他必填字段时抛出错误。
可选优化
模型类名VerificatonToken存在拼写错误(正确拼写应为VerificationToken),不影响当前运行,但建议修正以符合代码规范。
修复后流程验证
- 用户提交注册信息后,PatientSerializer正常保存
is_active=False的用户记录 - TokenSerializer接收到正确类型的用户ID和匹配的字段名,校验通过后保存验证令牌
- 触发SendGrid发信逻辑,正常返回200状态码,不会再走到403错误分支
- 用户点击邮件链接时,可正确匹配到验证令牌,将用户
is_active字段置为True,完成邮箱验证
内容的提问来源于stack exchange,提问作者falcon
相关产品推荐
相关产品推荐

