From 6ac79b822325784ad145ff0ad064127750c4f7e0 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 2 Dec 2014 09:19:59 +0000 Subject: [PATCH] Document Field.fail(). Closes #2147. --- docs/api-guide/fields.md | 49 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 391a52e52..aa5cc84ea 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -453,7 +453,7 @@ If you want to create a custom field, you'll need to subclass `Field` and then o The `.to_representation()` method is called to convert the initial datatype into a primitive, serializable datatype. -The `to_internal_value()` method is called to restore a primitive datatype into its internal python representation. +The `to_internal_value()` method is called to restore a primitive datatype into its internal python representation. This method should raise a `serializer.ValidationError` if the data is invalid. Note that the `WritableField` class that was present in version 2.x no longer exists. You should subclass `Field` and override `to_internal_value()` if the field supports data input. @@ -498,6 +498,53 @@ As an example, let's create a field that can be used represent the class name of """ return obj.__class__.__name__ +#### Raising validation errors + +Our `ColorField` class above currently does not perform any data validation. +To indicate invalid data, we should raise a `serializers.ValidationError`, like so: + + 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) + +The `.fail()` method is a shortcut for raising `ValidationError` that takes a message string from the `error_messages` dictionary. For example: + + default_error_messages = { + 'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}', + 'incorrect_format': 'Incorrect format. Expected `rgb(#,#,#)`.', + 'out_of_range': 'Value out of range. Must be between 0 and 255.' + } + + def to_internal_value(self, data): + if not isinstance(data, six.text_type): + msg = 'Incorrect type. Expected a string, but got %s' + self.fail('incorrect_type', input_type=type(data).__name__) + + if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data): + self.fail('incorrect_format') + + 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)]): + self.fail('out_of_range') + + return Color(red, green, blue) + +This style keeps you error messages more cleanly separated from your code, and should be preferred. + # Third party packages The following third party packages are also available.