关于 drf 框架中抛出异常的正确姿势

2020-01-09 09:41:32 +08:00
 kayseen

如题,之前使用的是 flask 框架, 抛出的异常都是自定义状态码和详细的异常信息, 抛出异常的格式为:

{
  "code": "1001",
  "data": {},
  "response": "请求不符合规范",
  "time": 2
}

然后现在学习使用 drf 框架, 比如在序列化器校验的时候抛出一个异常:

raise serializers.ValidationError('登录密码错误')

这个时候通过 postman 去故意触发这个报错,返回信息如下:

{
    "non_field_errors": [
        "登录密码错误"
    ]
}

然后我在序列化器中定义一个方法def validate_username去检验用户名称,在该方法中定义一个异常:

raise serializers.ValidationError('用户名称不符合规范')

然后故意去触发该异常,返回的信息如下:

{
    "username": [
        "用户名称不符合规范"
    ],
}

我现在就有点蒙了, 为什么返回异常的字段还会不断的变化?或者我应该怎么样捕获到它所有的异常来统一处理呢?网上有人说定义方法重新捕获,但是像如上的这种情况,连异常的字段信息都不一致,我该如何捕捉到具体的报错信息呢?

4810 次点击
所在节点    Python
18 条回复
lynskylate
2020-01-09 09:48:38 +08:00
你定义的 validate username 检查的是定义的 model 中 username 这个 field,drf 对于每个 field 都会检查,抛出的错误中 key 是检查失败的 field 名。
Jammar
2020-01-09 09:53:25 +08:00
抛出异常上层捕获异常
kayseen
2020-01-09 09:55:04 +08:00
@lynskylate
是的, 我在定义的`def validate`方法中抛出的异常字段名为`non_field_errors`, 请教一下关于 drf 的异常你是怎么处理的?
kayseen
2020-01-09 09:57:41 +08:00
@Jammar
你好, 这个思想我知道,我在上层捕获到的异常具体为:
```python
{'non_field_errors': [ErrorDetail(string='登录密码错误', code='invalid')]}
```
然后就获取不到 string 的具体信息了......
lynskylate
2020-01-09 10:00:13 +08:00
@kayseen drf 可以定义统一处理异常的函数,也有定义处理响应的地方。
hccsoul
2020-01-09 10:52:12 +08:00
第一瞬间看成 dnf,臭打游戏的没救了--
Hstar
2020-01-09 10:59:31 +08:00
建议你手动写一个 view,直接 raise Exception 的那种。

你所说的字段变化是 ValidationError 的特性,分别理解比较容易。
stephenyin
2020-01-09 12:10:10 +08:00
看见中出就进来了
Rand01ph
2020-01-09 13:27:02 +08:00
我这边都是直接在业务逻辑 raise 自定义异常,然后定义自定义异常处理函数,根据不同的异常生成返回.
Jammar
2020-01-09 15:51:56 +08:00
设置里面 drf 的设置配置这个字段'EXCEPTION_HANDLER'
lgh
2020-01-10 00:04:48 +08:00
kayseen
2020-01-10 10:47:06 +08:00
@hccsoul

@stephenyin

你们可真秀啊~
kayseen
2020-01-10 10:48:20 +08:00
@Rand01ph
你好,我想问的好像就是你说的这个,请问你是不是在下面的这个函数中定义的处理?

```python
from rest_framework.views import exception_handler

def custom_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)

# Now add the HTTP status code to the response.
if response is not None:
response.data['status_code'] = response.status_code

return response
```
Rand01ph
2020-01-14 10:04:31 +08:00
@kayseen 是的,是这个功能.
然后配置 `EXCEPTION_HANDLER`
leinal
2020-02-17 16:37:56 +08:00
想问下楼主,这个问题搞定了吗?目前也是这个问题。
kayseen
2020-02-18 10:14:53 +08:00
没有(>﹏<) 你搞定的话麻烦说下
kayseen
2020-02-18 10:15:18 +08:00
@leinal 没有(>﹏<) 你搞定的话麻烦说下
sxy960806
2020-02-27 22:44:18 +08:00
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response:
detail = response.data.get('detail')
non_field_errors = response.data.get('non_field_errors')
# 异常响应
if detail:
return Response({'response': detail, 'data': {}, 'code': '1001'})
elif non_field_errors:
return Response({'response': non_field_errors[0], 'data': {}, 'code': '1001'})
else:
return Response({'response': '接口参数错误', 'data': {}, 'code': '1001', 'tips': response.data})
return response


可以按照我这个思路来添加异常处理
效果如下:
# 登陆失败
{
"response": "无法使用提供的认证信息登录。",
"data": {},
"code": "1001"
}
# 开发阶段字段不完整或字段校验错误
{
"response": "接口参数错误",
"data": {},
"code": "1001",
"tips": {
"end_date": [
"该字段是必填项。"
],
"priority": [
"该字段是必填项。"
],
"auditor": [
"该字段是必填项。"
]
}
}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/636353

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX