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"
【讨论】:
classModelSerializerOptions
在 Django-rest-framework 版本中不可用。
注意:您可能希望为 Char 字段同时设置 required
和 blank
。
来自文档:“请记住,如果该字段已在序列化程序类上显式声明,则 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 序列化器