升级到Django 3.2后API测试失败,response.data['detail']格式异常
问题原因
- Django 3.2 会话失效规则变更:3.2版本新增了用户核心字段变更后自动失效所有关联会话的逻辑,你在测试用例中修改
is_superuser属性并调用save()后,原setUp中登录的会话被直接失效,导致后续请求处于未登录状态,DRF因此返回Authentication credentials were not provided的错误。状态码为403而非401是DRF的默认行为:未携带任何认证凭据时,权限校验失败会返回403而非401。 - 会话权限缓存未更新:Django 3.2优化了权限查询逻辑,用户登录后权限数据会缓存到session中,不会实时同步数据库的权限变更。你给用户添加权限后,当前会话的缓存还是旧的无权限状态,因此第二次请求仍然返回403。
- DRF 返回结构变化:升级后DRF版本同步更新,
detail字段默认返回ErrorDetail类型对象而非直接返回字符串,导致原字符串对比的断言失败。 - 登录参数不规范:原
setUp中登录代码self.client.login(username=self.user, password="test")传入的username参数是User对象而非字符串类型的用户名,老版本Django会自动将对象转为字符串兼容,3.2版本严格校验参数类型,虽然本次login返回True,但存在会话状态异常的隐患。
解决方案
- 修正登录参数
将setUp中的登录代码修正为传入字符串类型的用户名:
def setUp(self): self.user = User.objects.get(username="test-user") # 修正参数,传入username字符串 self.client.login(username=self.user.username, password="test")
- 修改用户属性后刷新会话
每次修改用户is_superuser、权限、密码等核心属性后,手动重新登录刷新会话,避免会话失效或缓存不更新:
self.user.is_superuser = False self.user.save() # 重新登录刷新会话 self.client.login(username=self.user.username, password="test") self.assertEqual(self.user.get_all_permissions(), set()) put_url = reverse(..., kwargs={"pk": 1}) # 后续请求逻辑不变
给用户添加权限后也执行相同的重新登录操作:
p = Permission.objects.get(codename="view_...") self.user.user_permissions.add(p) # 重新登录刷新权限缓存 self.client.login(username=self.user.username, password="test") response = self.client.get(retrieve_url) self.assertEqual(response.status_code, status.HTTP_200_OK)
- 适配ErrorDetail类型的断言
修改断言逻辑,将detail字段转为字符串后再对比:
self.assertEqual(str(response.data["detail"]), "You do not have permission to perform this action.")
如果需要全局返回字符串类型的detail,可以自定义DRF异常处理器:
# your_project/utils/exceptions.py from rest_framework.views import exception_handler def custom_exception_handler(exc, context): response = exception_handler(exc, context) if response is not None and 'detail' in response.data: response.data['detail'] = str(response.data['detail']) return response
在settings.py中注册该处理器:
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'your_project.utils.exceptions.custom_exception_handler', # 其余配置不变 }
内容的提问来源于stack exchange,提问作者mike john harry
相关产品推荐
相关产品推荐

