django rest framework: set field-level error from serializer validate() method

烂漫一生 提交于 2019-12-03 09:04:51

问题


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

回答1:


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.




回答2:


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.




回答3:


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



回答4:


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



来源:https://stackoverflow.com/questions/28179619/django-rest-framework-set-field-level-error-from-serializer-validate-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!