FutureMind / drf-friendly-errors

Extension for Django REST framework error display
MIT License
129 stars 58 forks source link

Crash when raising ValidationError in a custom field's to_internal_value() #8

Open cameel opened 8 years ago

cameel commented 8 years ago

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'
jsynowiec commented 8 years ago

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.