2014-11-15 7 views
16

Scenariusz jest dość prosty:Własne komunikaty o błędach w Serializatorze Django Rest Framework

Mam model z pewnymi polami, które są wymagane. Powiedzmy, że jednym z nich jest TextField, który nie może być blank. Mam również ModelSerializer (Django Rest Framework), który reprezentuje ten model.

Gdy do ustawiania tego pola przez moduł szeregowy używany jest pusty łańcuch, zwracany błąd pochodzi z samego modelu (This field can't be blank).

Chciałbym przesłonić komunikaty o błędach tylko na poziomie serializera, bez potrzeby bezpośredniego określania każdego pola w serializatorze (co moim zdaniem jest niezgodne z zasadą DRY), konieczności napisania metody validate_ dla każdego pole i podnieś moją własną ValidationError lub konieczność zmiany komunikatów o błędach na poziomie Model (ponieważ czasami kontekst komunikatu o błędzie ma znaczenie dla mojego przypadku użycia, a komunikat o błędzie powinien zostać podany odpowiednio).

Innymi słowy, czy istnieje sposób, aby zastąpić komunikaty o błędach na poziomie serializer tak proste, jak to jest dla 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 dzwoni django weryfikatorów polu w czasie walidacji. Więc błędy będą pochodzić stąd, nie z DRF. Chodzi o to, aby spróbować określić komunikat o błędzie na poziomie modelu lub pola, ponieważ jak widzę, nie ma sposobu na zastąpienie tych komunikatów za pomocą DRF. – coldmind

Odpowiedz

16

EDIT: widzę, że ta kwestia nadal odbiera pewne poglądy, więc ważne jest, aby pamiętać, że nie ma innego podejścia, znacznie czystsze niż oryginalny odpowiedzi napisałem tutaj.

można po prostu użyć atrybutu Meta klasy w serializer za extra_kwargs, tak:

class UserSerializer(ModelSerializer): 

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

odpowiedź oryginalny:

Korzystanie odpowiedź @mariodev „s I stworzył nową klasę w moim projekcie to robi:

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) 

Pierwsza z nich daje możliwość dodania nowego Meta atrybut klasy serializera, tak jak w przypadku ModelForm. Drugi dziedziczy po ModelSerializer i używa techniki @ mariodev do aktualizacji komunikatów o błędach.

Wszystko jest do zrobienia, jest po prostu odziedziczyć, i zrobić coś takiego:

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

klasa' ModelSerializerOptions' nie jest dostępna w wersji Django-rest-framework. –

14

W swojej serializatora:

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' 

Proszę zauważyć, że niektóre komunikaty o błędach składają się z następujących znaków zastępczych:

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

dla BooleanField.

Musisz więc przejść ponad default_error_messages część w każdym typie pola w DRF's fields.py, aby użyć go poprawnie.

+0

Muszę przyznać, że to nie jest tak czyste, jak technika 'ModelForm', ale robi to, co jest mi potrzebne –

6

unique zdawała się być ignorowane od error_messages, więc musiałem wziąć inne podejście.

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

To prostsze (jeszcze mniej elastyczna, mniej wielokrotnego użytku) niż @ Gabriel-Amram, ale znacznie mniej hacky niż @ mariodev jest.

2

Innym podejściem do UniqueValidator (za korzystanie z 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

Tylko uwaga, ponieważ grałem z tym na chwilę, jeśli używasz coś jak URLField że tylko dodaje URLValidator, to robi „t wydają się użyć error_messages, więc zrobiłem coś podobnego do @ odpowiedź Hugo:

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

DRF3.0 oczekuje od nas, aby wyraźnie określić weryfikatorów dla pól jeżeli chcemy zastąpić domyślny modelu weryfikatorów. Można to zrobić, przekazując extra_kwargs i jawnie definiując walidatory dla któregokolwiek pola . Ponadto można nawet określić swój własny walidator, które mogą być ponownie wykorzystane ponownie w różnych dziedzinach, a nawet inne serializers

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