45

I have a serializer that validates fields based on the values of other fields, In the error response I would like to show each field error as a field error as opposed to showing everything under "non_field_errors" which is what would happen if I were to raise a ValidationError in the object-level validate method. Below is an illustration of what I'm trying to achieve:

MySerializer(ModelSerializer):
    ...
    def validate(self, data):
        field_val1 = data['field_val1']
        field_val2 = data['field_val2']
        if not self._is_field_valid(field_val1, field_val2):
            # The below line is how I would do what I want with Django
            # Forms, however, it's not valid in DRF
            self._errors['field_val1'] = 'this field is not valid'

The desired error response is:

{'field_val1': ['this field is not valid']}

4 Answers 4

75

I figured it out, on this page of the documentation in the "BaseSerializer" section, there's an example that shows ValidationError can take a dictionary argument upon initialization.

If I raise ValidationError({'field_val1': ['this field is not valid']}) I get the JSON response I want.

Sign up to request clarification or add additional context in comments.

3 Comments

Also works well to mimic 'This field is required' responses.
@MarkMishyn no need to, but it's convention set by Django and followed by Rest Framework for fields errors to be lists of errors. But its up to your frontend/client logic to actually decide how to support them.
Note that by doing this you also have to handle translation yourself, unlike @frnhr's answer.
4

Similarly to the answer by @Jkk.jonah, this raises a ValidationError, but it reuses the original exception text without need to re-implement translations:

try:
    serializer.fields['field_val1'].fail('required')
except ValidationError as exc:
    raise ValidationError({
        'field_val1': exc.detail,
    })

By default (i.e. on rest_framework.fields.Field class), available keys are:

default_error_messages = {
    'required': _('This field is required.'),
    'null': _('This field may not be null.')
}

Subclasses can add their own error messages there (and Serializer is a subclass of Field).

BTW, new error messages will be automagically merged with existing (inherited) messages - won't be overridden as might be expected.

1 Comment

Using the built-in error messages is great for me because the translation is already there.
1

If you have logic that applies to all the fields, you can still get the desired result by doing this:

def validate(self, data):
    for key, value in data.items():
        # checks if value is empty
        if not value:
            raise serializers.ValidationError({key: "This field should not be left empty."})

    return data

Comments

0

In case you are using built-in validators in DRF (which are in-fact django core validators) you have to preprocess django ValidationError coming from validator with a function get_error_detail drf is using for this purpose.

def _validate_min_value(self, data, key):
        try:
            MinValueValidator(Decimal('0.01'))(data.get(key))
        except ValidationErrorDjango as exc:
            raise ValidationError(
                {key: get_error_detail(exc)}
            )

Note that ValidationErrorDjango is a ValidationError from django.core.exceptions, while ValidationError is a one from rest_framework.exceptions

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.