Django Rest Framework 序列化程序中的自定义错误消息

Posted

技术标签:

【中文标题】Django Rest Framework 序列化程序中的自定义错误消息【英文标题】:Custom error messages in Django Rest Framework serializer 【发布时间】:2015-01-12 16:05:31 【问题描述】:

场景非常简单:

我有一个模型,其中包含一些必填字段。假设其中一个是TextField,它不能是blank。 我还有一个代表该模型的ModelSerializer(Django Rest Framework)。

当使用空字符串通过序列化程序设置该字段时,返回的错误来自模型本身 (This field can't be blank)。

我想仅在序列化程序级别覆盖错误消息,而无需显式重新指定序列化程序中的每个字段(我认为这违反了 DRY 原则),必须编写一个validate_ 方法每个字段并提出我自己的ValidationError 或必须更改Model 级别中的错误消息(因为有时错误消息的上下文对我的用例很重要,应相应地给出错误消息)。

换句话说,有没有办法像ModelForm一样简单地覆盖序列化程序级别的错误消息:

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        error_messages = "field1": "required": _("For some reason this is a custom error message overriding the model's default")

【问题讨论】:

DRF 在验证时调用 django 字段验证器。所以错误将来自这里,而不是来自 DRF。这个想法是尝试在模型或字段级别指定错误消息,因为我可以看到没有办法用 DRF 覆盖这些消息。 【参考方案1】:

在您的序列化程序中:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User

    def __init__(self, *args, **kwargs):
        super(UserSerializer, self).__init__(*args, **kwargs)

        self.fields['username'].error_messages['required'] = u'My custom required msg'

请注意,一些错误消息包含%s 占位符,例如:

'invalid': _("'%s' value must be either True or False."),

BooleanField

因此,您需要检查 DRF 的 fields.py 中每个字段类型中的 default_error_messages 部分,才能正确使用它。

【讨论】:

我不得不承认这不像 ModelForm 技术那么干净,但它确实可以满足我的需要 唯一对我有用的东西!其他人没有。我正在使用djangorestframework==3.11.0【参考方案2】:

编辑:我看到这个问题仍然有一些观点,所以重要的是要注意还有另一种方法,比我在这里发布的原始答案更清晰。

您可以只使用序列化程序 Meta 类的 extra_kwargs 属性,如下所示:

class UserSerializer(ModelSerializer):

    class Meta:
        model = User
        extra_kwargs = "username": "error_messages": "required": "Give yourself a username"

原答案:

使用@mariodev 的回答,我在我的项目中创建了一个新的类:

from rest_framework.serializers import ModelSerializer, ModelSerializerOptions

class CustomErrorMessagesModelSerializerOptions(ModelSerializerOptions):
    """
    Meta class options for CustomErrorMessagesModelSerializerOptions
    """
    def __init__(self, meta):
        super(CustomErrorMessagesModelSerializerOptions, self).__init__(meta)
        self.error_messages = getattr(meta, 'error_messages', )

class CustomErrorMessagesModelSerializer(ModelSerializer):
    _options_class = CustomErrorMessagesModelSerializerOptions

    def __init__(self, *args, **kwargs):
        super(CustomErrorMessagesModelSerializer, self).__init__(*args, **kwargs)

        # Run through all error messages provided in the Meta class and update
        for field_name, err_dict in self.opts.error_messages.iteritems():
            self.fields[field_name].error_messages.update(err_dict)

第一个提供了向序列化程序添加新的Meta 类属性的可能性,就像ModelForm 一样。 第二个继承自ModelSerializer,并使用@mariodev 的技术来更新错误消息。

剩下要做的就是继承它,然后做类似的事情:

class UserSerializer(CustomErrorMessagesModelSerializer):
    class Meta:
        model = User
        error_messages = "username": "required": "Give yourself a username"

【讨论】:

class ModelSerializerOptions 在 Django-rest-framework 版本中不可用。 注意:您可能希望为 Char 字段同时设置 requiredblank 来自文档:“请记住,如果该字段已在序列化程序类上显式声明,则 extra_kwargs 选项将被忽略。”【参考方案3】:

unique 似乎被 error_messages 忽略了,所以我不得不采取不同的方法。

email = serializers.EmailField(validators=[
    UniqueValidator(
        queryset=models.Client.objects.all(),
        message="My custom error",
    )]
)

它比 @gabriel-amram 的更简单(但灵活性较差,可重用性较差),但远不如 @mariodev 的 hacky。

【讨论】:

这对我有用 - 20.03.2020。我想知道为什么不能使用extra_kwargs 覆盖“唯一”错误消息?【参考方案4】:

UniqueValidator 的另一种方法(与 ModelSerializer 一起使用):

def __init__(self, *args, **kwargs):
    super(UserSerializer, self).__init__(*args, **kwargs)
    # Find UniqueValidator and set custom message
    for validator in self.fields['email'].validators:
        if isinstance(validator, validators.UniqueValidator):
            validator.message = _('This email already exist on this site')

【讨论】:

【参考方案5】:

只是一个注释,因为我玩了一段时间,如果你使用类似 URLField 的东西,它只是添加了一个 URLValidator,它似乎没有使用error_messages,所以我做了类似于@Hugo 的回答:

class Meta:
    extra_kwargs = "url_field": "validators": [validators.URLValidator(message="My error message")]

【讨论】:

【参考方案6】:

如果我们希望覆盖默认模型验证器,DRF3.0 期望我们明确定义字段的验证器。这可以通过传递 extra_kwargs 并明确定义任何字段的验证器来完成 你似乎有必要。此外,您甚至可以指定自己的自定义验证器,这些验证器可以再次用于不同的字段甚至其他序列化器

http://www.django-rest-framework.org/api-guide/serializers/#validation

http://www.django-rest-framework.org/api-guide/validators/#validation-in-rest-framework

# my_app/validators.py
def validate_required(value):
    # whatever validation logic you need
    if value == '' or value is None:
        raise serializers.ValidationError('This field is required.')

# my_app/serializers.py
class MyModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = MyModel
        extra_kwargs = "field1": "validators": [validators.validate_required,]

【讨论】:

【参考方案7】:

我尝试创建一个简单的Serializer 而不是ModelSerializer。可能是因为 Gabriel Amram 接受的extra_kwargs 答案对我不起作用。 @mariodev 的另一个最佳答案确实有效,但我正在寻找一个更优雅的解决方案并找到了一个。原来Field 类接受error_messages 作为参数,这是一个覆盖默认错误消息的字典。这是reference to the docs。它与接受的答案中描述的格式相同。这是一个例子:

from rest_framework import serializers

class MySerializer(serializers.Serializer):
    client_id = serializers.IntegerField(required=True, error_messages='required': 'Custom error message')

【讨论】:

【参考方案8】:

我刚刚花了一个小时来解决这个问题,所以我想我会在这里发布一个更新,以防其他人发现它有用。

我正在使用 djangorestframework 版本 3.10.3,无论出于何种原因,似乎 drf 不再使用 error_messages 字典中的“必需”键来允许自定义缺失值的错误消息。相反,它使用“空白”。

class SampleSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = SampleModel
        fields = (
            'description',
        )

        extra_kwargs = 
            'description': 'error_messages': 'blank': "Please provide a description",
        

【讨论】:

【参考方案9】:

这是继承模型错误消息的代码。 还有一个模块,所以如果你想下载它。 如果有问题,请留在 cmets 中。

https://pypi.org/project/django-rest-inherits-error-messages/#files

from rest_framework import serializers
from rest_framework.relations import HyperlinkedRelatedField
from rest_framework.utils.field_mapping import get_nested_relation_kwargs

class InheritsModelSerializer(serializers.ModelSerializer):
    def build_field(self, field_name, info, model_class, nested_depth):
        '''
        inherits the error_messages of the model
        '''
        result: tuple = super().build_field(field_name, info, model_class, nested_depth)

        field = model_class._meta.get_field(field_name)
        error_messages = field.error_messages

        if error_messages:
            result[1]['error_messages'] = field.error_messages

        return result

【讨论】:

以上是关于Django Rest Framework 序列化程序中的自定义错误消息的主要内容,如果未能解决你的问题,请参考以下文章

python django-rest-framework 3.3.3 更新嵌套序列化程序

django-rest-framework、多表模型继承、ModelSerializers 和嵌套序列化器

Django.rest_framework:如何序列化一对多?

Django 序列化器与 rest_framework 序列化器

Django-Rest-Framework 中的序列化程序问题

django.core 序列化器和 Django Rest Framework 序列化器之间的区别