【问题标题】:Django Rest Framework custom response for validation failure验证失败的 Django Rest Framework 自定义响应
【发布时间】:2018-02-18 01:22:53
【问题描述】:

背景

我是 Django 和其他框架的新手,我正在尝试使用 Django Rest 框架为移动应用构建注册和登录的 API 演示。

我想要

我使用APIViewModelSerializer,注册的参数和约束是

email <required, unique>,
username <required, unique>,
password <required, unique>,

在这里,我的需求集中在异常上,我想获得一个自定义错误代码来指示哪些验证(必需或唯一)失败。

例如

当我发送参数时:

username="", (leaves it blank)
password=123, 
email="xxx@yyy.com"

这将导致required 验证失败,并且 JSON 响应返回类似

"username": [
    "This field may not be blank."
]

但是,我希望 JSON 响应类似于

{
    error_code: 1,
    msg: "blah blah blah"
}

这样,移动应用就可以根据error_code为所欲为。

问题

我发现,在框架的验证实现内部,验证失败(所有字段验证失败)都被转化为纯文本并打包在一个数组中,我无法得到具体的异常(如用户名要求异常),而且我无法在响应中生成error_code。

那么,有什么办法可以捕捉到具体的异常吗?

【问题讨论】:

  • 在响应中包含这些错误代码有什么具体原因吗?为什么客户端不能使用http错误码?
  • @mikedanylov http 错误代码会有所帮助,但我希望错误更具体,例如 required 验证失败或 unique 验证失败。默认的http错误码400似乎只是告诉我一些验证失败,不够具体
  • 那么您可能需要为所有字段编写自定义验证。可以通过覆盖每个字段的序列化程序的验证方法来完成。例如,对于密码,您需要覆盖方法validate_password,然后您可以随意格式化字段错误对象。

标签: python django validation django-rest-framework


【解决方案1】:

我找到了解决方法。

username = serializers.CharField(
    validators=[
        UniqueValidator(
            queryset=Account.objects.all(),
            message=convert_dictionary_to_json_string({
                'error_code': ErrorCode.parameter.value,
                'msg': 'username exists',
            }),
        ),
    ],
    # ...other validators
)

由于我们只能传递字符串类型的消息,在验证器中,我们可以:

  1. 建立一个包含我们需要的错误信息的字典
  2. 将此字典转换为 JSON 字符串
  3. 只需将 JSON 字符串传递给 message 字段

之后,在view代码中,如果验证失败:

  1. 我们将serializer.errors中的错误消息(JSON字符串)转换为字典
  2. 将其打包到响应中

【讨论】:

    【解决方案2】:

    在您的序列化程序的to_internal_value 中,您可以捕获ValidatonErrors 并对其进行修改。

    class MySerializer(ModelSerializer):
    
        def to_internal_value(self, data):
            try:
                return super().to_internal_value(data)
            except serializers.ValidationError as err:
                # do something with the error messages
                # reraise with the modified ValidationError
                raise err
    

    http://www.django-rest-framework.org/api-guide/serializers/#overriding-serialization-and-deserialization-behavior

    【讨论】:

    • 谢谢,但我发现识别所需失败或唯一失败的线索是纯文本。有没有类似标志的东西可以告诉我所需的失败或独特的失败?
    • 纯文本包含在ValidationError.detail 属性中,该属性应该是字典或列表。您可以阅读源代码以准确了解如何访问所需的数据。 github.com/encode/django-rest-framework/blob/master/…
    【解决方案3】:

    你可以使用extra_kwargs

    代码

    class UserSerializer(ModelSerializer):
    
    class Meta:
        model = User
        extra_kwargs = {"username": {"error_messages": {"required": "Give yourself a username"}}}
    

    【讨论】:

    • 谢谢,但我还有什么需要做的吗?添加代码后它不起作用。