2014-11-15 6 views
16

Lo scenario è abbastanza straight-forward:messaggi di errore personalizzate in Django serializzatore Resto quadro

Ho un modello con alcuni campi che sono richiesti. Diciamo che uno di questi è uno TextField che non può essere blank. Ho anche un ModelSerializer (Django Rest Framework) che rappresenta quel modello.

Quando una stringa vuota viene utilizzata per impostare quel campo attraverso il serializzatore, l'errore restituito proviene dal modello stesso (This field can't be blank).

Desidero sovrascrivere i messaggi di errore solo a livello di serializzatore, senza la necessità di ridefinire esplicitamente ogni campo nel serializzatore (che credo sia contrario al principio DRY), dovendo scrivere un metodo validate_ per ciascun campo e aumentare il mio ValidationError o dover modificare i messaggi di errore nel livello Model (perché a volte il contesto del messaggio di errore è importante per il mio caso d'uso e il messaggio di errore dovrebbe essere dato di conseguenza).

In altre parole, c'è un modo per ignorare i messaggi di errore nel livello serializzatore così facile come lo è per 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")}} 
+0

DRF sta chiamando validatori dei campi Django al momento della convalida. Quindi gli errori arriveranno da qui, non da DRF. L'idea è provare a specificare un messaggio di errore a livello di modello o di campo, perché come posso vedere non c'è modo di ignorare questi messaggi con DRF. – coldmind

risposta

16

EDIT: Vedo che questa domanda riceve ancora alcune visualizzazioni, quindi è importante notare che c'è un altro approccio, molto più pulito rispetto alla risposta originale che ho postato qui.

si può semplicemente utilizzare l'attributo extra_kwargs della classe Meta del serializzatore, in questo modo:

class UserSerializer(ModelSerializer): 

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

risposta originale:

Utilizzando risposta @mariodev l' ho creato una nuova classe nel mio progetto che lo fa:

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 prima si dà la possibilità di aggiungere un nuovo Meta attributo di classe al serializzatore come con lo ModelForm. Il secondo eredita da ModelSerializer e utilizza la tecnica di @ mariodev per aggiornare i messaggi di errore.

Tutto è lasciato fare, è solo ereditare, e fare qualcosa di simile:

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

La classe' ModelSerializerOptions' non è disponibile nella versione di Django-rest-framework. –

14

Nel vostro serializzatore:

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' 

Si prega di notare che alcuni messaggi di errore sono composti da %s segnaposti come:

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

per BooleanField.

Quindi è necessario andare oltre default_error_messages parte in ogni tipo di campo in fields.py del DRF, per usarlo correttamente.

+0

Devo ammettere che non è pulito come la tecnica 'ModelForm', ma fa quello che mi serve. –

6

unique sembrava essere ignorato da error_messages, così ho dovuto adottare un approccio diverso.

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

E 'più semplice (ancora meno flessibili, meno riutilizzabili) rispetto @ gabriel-Amram di, ma molto meno di quanto hacky @ mariodev di.

2

Un altro approccio per UniqueValidator (per l'utilizzo con 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') 
0

Solo una nota da quando ho giocato con questo per un po ', se stai usando qualcosa come un URLField che aggiunge solo un URLValidator, doesn 't sembrano utilizzare il error_messages, così ho fatto qualcosa di simile a @ risposta di Hugo:

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

DRF3.0 si aspetta di definire in modo esplicito i validatori per i campi se vogliamo ignorare i validatori modello predefinito. Questo può essere fatto passando extra_kwargs e definendo in modo esplicito i validatori per qualunque campo ti sembra necessario. Inoltre è possibile anche specificare il proprio validatore personalizzato che può essere riutilizzato per i diversi campi o anche altri Serializzatori

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,]}}