【问题标题】:Custom error messages in Django Rest Framework serializerDjango Rest Framework 序列化程序中的自定义错误消息
【发布时间】: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 覆盖这些消息。

标签: django django-rest-framework


【解决方案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
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-11-28
              • 1970-01-01
              • 1970-01-01
              • 2020-05-23
              • 1970-01-01
              • 2013-08-03
              • 1970-01-01
              • 2019-05-23
              相关资源
              最近更新 更多