@@ -561,6 +561,8 @@ Note that the `WritableField` class that was present in version 2.x no longer ex
561561
562562##Examples
563563
564+ ###A Basic Custom Field
565+
564566Let's look at an example of serializing a class that represents an RGB color value:
565567
566568class Color(object):
@@ -600,7 +602,7 @@ As an example, let's create a field that can be used to represent the class name
600602 """
601603 return obj.__class__.__name__
602604
603- #### Raising validation errors
605+ ###Raising validation errors
604606
605607Our` ColorField ` class above currently does not perform any data validation.
606608To indicate invalid data, we should raise a` serializers.ValidationError ` , like so:
@@ -646,6 +648,75 @@ The `.fail()` method is a shortcut for raising `ValidationError` that takes a me
646648
647649This style keeps your error messages cleaner and more separated from your code, and should be preferred.
648650
651+ ###Using` source='*' `
652+
653+ Here we'll take an example of a_ flat_ ` DataPoint ` model with` x_coordinate ` and` y_coordinate ` attributes.
654+
655+ class DataPoint(models.Model):
656+ label = models.CharField(max_length=50)
657+ x_coordinate = models.SmallIntegerField()
658+ y_coordinate = models.SmallIntegerField()
659+
660+ Using a custom field and` source='*' ` we can provide a nested representation of
661+ the coordinate pair:
662+
663+ class CoordinateField(serializers.Field):
664+
665+ def to_representation(self, obj):
666+ ret = {
667+ "x": obj.x_coordinate,
668+ "y": obj.y_coordinate
669+ }
670+ return ret
671+
672+ def to_internal_value(self, data):
673+ ret = {
674+ "x_coordinate": data["x"],
675+ "y_coordinate": data["y"],
676+ }
677+ return ret
678+
679+
680+ class DataPointSerializer(serializers.ModelSerializer):
681+ coordinates = CoordinateField(source='*')
682+
683+ class Meta:
684+ model = DataPoint
685+ fields = ['label', 'coordinates']
686+
687+ Note that this example doesn't handle validation. Partly for that reason, in a
688+ real project, the coordinate nesting might be better handled with a nested serialiser using two
689+ ` IntegerField ` instances, each with` source='*' ` .
690+
691+ The key points from the example, though, are:
692+
693+ * ` to_representation ` is passed the entire` DataPoint ` object must map from that
694+ to the desired output.
695+
696+ >>> instance = DataPoint(label='Example', x_coordinate=1, y_coordinate=2)
697+ >>> out_serializer = DataPointSerializer(instance)
698+ >>> out_serializer.data
699+ ReturnDict([('label', 'testing'), ('coordinates', {'x': 1, 'y': 2})])
700+
701+ * Unless our field is to be read-only,` to_internal_value ` must map back to a dict
702+ suitable for updating our target object. With` source='*' ` , the return from
703+ ` to_internal_value ` will update the root validated data dictionary, rather than a single key.
704+
705+ >>> data = {
706+ ... "label": "Second Example",
707+ ... "coordinates": {
708+ ... "x": 3,
709+ ... "y": 4,
710+ ... }
711+ ... }
712+ >>> in_serializer = DataPointSerializer(data=data)
713+ >>> in_serializer.is_valid()
714+ True
715+ >>> in_serializer.validated_data
716+ OrderedDict([('label', 'Second Example'),
717+ ('y_coordinate', 4),
718+ ('x_coordinate', 3)])
719+
649720#Third party packages
650721
651722The following third party packages are also available.