drf-friendly-errors
drf-friendly-errors copied to clipboard
Crash when raising ValidationError in a custom field's to_internal_value()
Django REST Framework recommends raising a ValidationError
in to_internal_value()
method of a custom field to report a validation error (see DRF > API Guide > Fields > Raising validation errors). The plugin crashes with AttributeError
when I do that. It assumes that the serializer has a method called validate_<field name>
while it does not.
How to reproduce
Here's a custom field example taken from DRF docs (linked above). Imports and serializers added by me:
# color_serializers.py
import re
import six
from rest_framework.serializers import Field, Serializer, ValidationError
from rest_framework_friendly_errors.mixins import FriendlyErrorMessagesMixin
class Color(object):
"""
A color represented in the RGB colorspace.
"""
def __init__(self, red, green, blue):
assert(red >= 0 and green >= 0 and blue >= 0)
assert(red < 256 and green < 256 and blue < 256)
self.red, self.green, self.blue = red, green, blue
class ColorField(Field):
"""
Color objects are serialized into 'rgb(#, #, #)' notation.
"""
def to_representation(self, obj):
return "rgb(%d, %d, %d)" % (obj.red, obj.green, obj.blue)
def to_internal_value(self, data):
if not isinstance(data, six.text_type):
msg = 'Incorrect type. Expected a string, but got %s'
raise ValidationError(msg % type(data).__name__)
if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):
raise ValidationError('Incorrect format. Expected `rgb(#,#,#)`.')
data = data.strip('rgb(').rstrip(')')
red, green, blue = [int(col) for col in data.split(',')]
if any([col > 255 or col < 0 for col in (red, green, blue)]):
raise ValidationError('Value out of range. Must be between 0 and 255.')
return Color(red, green, blue)
class ColorSerializer(Serializer):
color = ColorField()
class FriendlyColorSerializer(FriendlyErrorMessagesMixin, Serializer):
color = ColorField()
Normal serializer works as expected
from .color_serializers import ColorSerializer
color_serializer = ColorSerializer(data = {'color': u'not a color'})
color_serializer.is_valid(raise_exception = True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/cameel/.virtualenvs/test/lib/python2.7/site-packages/rest_framework/serializers.py", line 222, in is_valid
raise ValidationError(self.errors)
ValidationError: {'color': [u'Incorrect format. Expected `rgb(#,#,#)`.']}
Serializer with FriendlyErrorMessagesMixin raises AttributeError
from .color_serializers import FriendlyColorSerializer
friendly_color_serializer = FriendlyColorSerializer(data = {'color': u'not a color'})
friendly_color_serializer.is_valid(raise_exception = True)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/cameel/.virtualenvs/test/lib/python2.7/site-packages/rest_framework/serializers.py", line 222, in is_valid
raise ValidationError(self.errors)
File "/home/cameel/.virtualenvs/test/lib/python2.7/site-packages/rest_framework_friendly_errors/mixins.py", line 23, in errors
pretty_errors = self.build_pretty_errors(ugly_errors)
File "/home/cameel/.virtualenvs/test/lib/python2.7/site-packages/rest_framework_friendly_errors/mixins.py", line 204, in build_pretty_errors
self.get_field_error_entries(errors[error_type], field),
File "/home/cameel/.virtualenvs/test/lib/python2.7/site-packages/rest_framework_friendly_errors/mixins.py", line 178, in get_field_error_entries
return [self.get_field_error_entry(error, field) for error in errors]
File "/home/cameel/.virtualenvs/test/lib/python2.7/site-packages/rest_framework_friendly_errors/mixins.py", line 166, in get_field_error_entry
validator = getattr(self, "validate_%s" % field.field_name)
AttributeError: 'FriendlyColorSerializer' object has no attribute 'validate_color'
Thanks for reporting it. We'll look into this but I can't give any estimates right now. Our core maintainer of this module is currently occupied with other tasks.
Feel free to send a PR with a fix proposal if you have one.