Le scénario est assez simple:
J'ai un modèle avec certains champs obligatoires. Supposons que l'un d'eux est une TextField
qui ne peut pas être blank
. J'ai aussi une ModelSerializer
(Django Rest Framework) qui représente ce modèle.
Lorsqu'une chaîne vide est utilisée pour définir ce champ via le sérialiseur, l'erreur renvoyée provient du modèle lui-même (This field can't be blank
).
Je voudrais remplacer les messages d'erreur uniquement au niveau du sérialiseur, sans qu'il soit nécessaire de re-spécifier explicitement chaque champ du sérialiseur (ce qui, selon moi, va à l'encontre du principe DRY), ce qui oblige à écrire une méthode validate_
pour chaque champ et lever ma propre ValidationError
ou devoir modifier les messages d'erreur du niveau Model
(car parfois le contexte du message d'erreur est important pour mon cas d'utilisation et le message d'erreur doit être donné en conséquence).
En d'autres termes, existe-t-il un moyen de remplacer les messages d'erreur au niveau du sérialiseur aussi facilement que pour un 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")}}
EDIT: Je vois que cette question suscite encore quelques critiques, il est donc important de noter qu'il existe une autre approche, beaucoup plus nette que la réponse originale que j'ai postée ici.
Vous pouvez simplement utiliser l'attribut extra_kwargs de la classe Meta du sérialiseur, comme suit:
class UserSerializer(ModelSerializer):
class Meta:
model = User
extra_kwargs = {"username": {"error_messages": {"required": "Give yourself a username"}}}
Réponse originale:
En utilisant la réponse de @mariodev, j'ai créé une nouvelle classe dans mon projet:
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)
La première offre la possibilité d’ajouter un nouvel attribut de classe Meta
au sérialiseur, comme pour ModelForm
. Le second hérite de ModelSerializer
et utilise la technique de @ mariodev pour mettre à jour les messages d'erreur.
Tout est laissé à faire, c'est juste hériter, et faire quelque chose comme ça:
class UserSerializer(CustomErrorMessagesModelSerializer):
class Meta:
model = User
error_messages = {"username": {"required": "Give yourself a username"}}
Dans votre sérialiseur:
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'
Veuillez noter que certains messages d'erreur consistent en des espaces réservés %s
tels que:
'invalid': _("'%s' value must be either True or False."),
pour BooleanField
.
Vous devez donc parcourir la partie default_error_messages
dans chaque type de champ dans le fields.py
du DRF pour pouvoir l'utiliser correctement.
unique
semblait être ignoré de error_messages
, alors j'ai dû adopter une approche différente.
email = serializers.EmailField(validators=[
UniqueValidator(
queryset=models.Client.objects.all(),
message="My custom error",
)]
)
C'est plus simple (mais moins souple, moins réutilisable) que celui de @ gabriel-amram, mais beaucoup moins hacky que celui de @ mariodev.
Une autre approche pour UniqueValidator (à utiliser avec 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')
J'ai essayé de créer un simple Serializer
plutôt qu'un ModelSerializer
. Probablement à cause de cela la réponse acceptée avec extra_kwargs
par Gabriel Amram n'a pas fonctionné pour moi. Une autre réponse de @mariodev a fonctionné, mais je recherchais une solution plus élégante et en trouvai une. Il s'avère que la classe Field
accepte error_messages
en tant que paramètre, qui est un dictionnaire qui remplace les messages d'erreur par défaut. Voici la référence aux documents . C'est le même format que décrit dans les réponses acceptées. Voici un exemple:
from rest_framework import serializers
class MySerializer(serializers.Serializer):
client_id = serializers.IntegerField(required=True, error_messages={'required': 'Custom error message'})
DRF3.0 attend de nous que nous définissions explicitement les validateurs des champs si nous souhaitons remplacer les validateurs de modèle par défaut. Cela peut être fait en passant extra_kwargs et en définissant explicitement les validateurs pour n'importe quel champ vous semblez nécessaire. Vous pouvez également spécifier votre propre validateur personnalisé qui pourra être réutilisé pour différents champs ou même pour d'autres sérialiseurs.
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,]}}
Juste une note depuis que je joue à ça depuis un moment, si vous utilisez quelque chose comme un URLField qui ajoute juste un URLValidator, il ne semble pas utiliser le error_messages
, alors j'ai fait quelque chose de similaire à la réponse de @ Hugo:
class Meta:
extra_kwargs = {"url_field": {"validators": [validators.URLValidator(message="My error message")]}}