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']}
Validation in Django REST framework serializers is handled a little differently to how validation works in Django's ModelForm class. With ModelForm the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class.
The easiest way to change the error style through all the view in your application is to always use serializer. is_valid(raise_exception=True) , and then implement a custom exception handler that defines how the error response is created.
The generic views use the raise_exception=True flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above. By default this exception results in a response with the HTTP status code "400 Bad Request".
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With