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

DRF中is_valid()为何需传raise_exception=True才能返回格式化错误

问题根因

两个场景的表现差异和is_valid()是否传raise_exception=True没有本质关系,核心问题出在密码修改视图的状态码使用错误,以及对raise_exception参数作用的认知偏差:

  • 电影接口校验失败时手动返回的是400 Bad Request状态码,这是HTTP标准里定义的客户端请求参数错误专用状态码,所有HTTP客户端(包括Postman、浏览器)都会正常解析该状态码对应的响应体,所以不需要加raise_exception=True也能正常看到格式化的错误信息。
  • 密码修改接口的原始逻辑里,校验失败分支手动返回的是304 Not Modified状态码,这个状态码是HTTP缓存协商流程专用的,RFC规范明确要求304响应绝对不能携带响应体。所有标准HTTP客户端收到304状态码时,会直接忽略响应返回的内容、读取本地缓存的资源,所以你在Postman里会看到无响应的表现,和序列化器的校验逻辑没有任何关系。

为什么加了raise_exception=True就恢复正常

当给is_valid()传入raise_exception=True参数时,序列化器校验失败不会返回False走到你写的304返回分支,而是直接抛出ValidationError异常。这个异常会被DRF内置的全局异常处理器自动捕获,直接返回400状态码+格式化错误信息的标准响应,相当于绕过了你写的错误的304响应逻辑,所以才能正常展示错误。

额外的代码优化建议

  • 不要在序列化器的validate方法里做数据持久化操作:当前在密码校验通过后直接在validate里调用user.set_password()和user.save()是不符合DRF设计规范的,validate方法只应该做参数合法性校验,数据修改的逻辑应该写到序列化器的update/create方法中,由视图调用serializer.save()触发,避免校验流程中掺杂写操作导致的数据不一致问题。
  • 状态码使用要符合规范:304只能用于缓存协商场景,不能用来表示业务处理失败;密码修改是同步完成的操作,处理成功返回200 OK即可,不需要用202 Accepted(202用于异步处理、任务已提交但未完成的场景)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:45:37