Skip to content

Commit 6ac79b8

Browse files
committed
Document Field.fail(). Closes #2147.
1 parent f4fc467 commit 6ac79b8

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

docs/api-guide/fields.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ If you want to create a custom field, you'll need to subclass `Field` and then o
453453

454454
The `.to_representation()` method is called to convert the initial datatype into a primitive, serializable datatype.
455455

456-
The `to_internal_value()` method is called to restore a primitive datatype into its internal python representation.
456+
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.
457457

458458
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.
459459

@@ -498,6 +498,53 @@ As an example, let's create a field that can be used represent the class name of
498498
"""
499499
return obj.__class__.__name__
500500

501+
#### Raising validation errors
502+
503+
Our `ColorField` class above currently does not perform any data validation.
504+
To indicate invalid data, we should raise a `serializers.ValidationError`, like so:
505+
506+
def to_internal_value(self, data):
507+
if not isinstance(data, six.text_type):
508+
msg = 'Incorrect type. Expected a string, but got %s'
509+
raise ValidationError(msg % type(data).__name__)
510+
511+
if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):
512+
raise ValidationError('Incorrect format. Expected `rgb(#,#,#)`.')
513+
514+
data = data.strip('rgb(').rstrip(')')
515+
red, green, blue = [int(col) for col in data.split(',')]
516+
517+
if any([col > 255 or col < 0 for col in (red, green, blue)]):
518+
raise ValidationError('Value out of range. Must be between 0 and 255.')
519+
520+
return Color(red, green, blue)
521+
522+
The `.fail()` method is a shortcut for raising `ValidationError` that takes a message string from the `error_messages` dictionary. For example:
523+
524+
default_error_messages = {
525+
'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}',
526+
'incorrect_format': 'Incorrect format. Expected `rgb(#,#,#)`.',
527+
'out_of_range': 'Value out of range. Must be between 0 and 255.'
528+
}
529+
530+
def to_internal_value(self, data):
531+
if not isinstance(data, six.text_type):
532+
msg = 'Incorrect type. Expected a string, but got %s'
533+
self.fail('incorrect_type', input_type=type(data).__name__)
534+
535+
if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):
536+
self.fail('incorrect_format')
537+
538+
data = data.strip('rgb(').rstrip(')')
539+
red, green, blue = [int(col) for col in data.split(',')]
540+
541+
if any([col > 255 or col < 0 for col in (red, green, blue)]):
542+
self.fail('out_of_range')
543+
544+
return Color(red, green, blue)
545+
546+
This style keeps you error messages more cleanly separated from your code, and should be preferred.
547+
501548
# Third party packages
502549

503550
The following third party packages are also available.

0 commit comments

Comments
 (0)