@@ -561,6 +561,8 @@ Note that the `WritableField` class that was present in version 2.x no longer ex
561
561
562
562
## Examples
563
563
564
+ ### A Basic Custom Field
565
+
564
566
Let's look at an example of serializing a class that represents an RGB color value:
565
567
566
568
class Color(object):
@@ -600,7 +602,7 @@ As an example, let's create a field that can be used to represent the class name
600
602
"""
601
603
return obj.__class__.__name__
602
604
603
- #### Raising validation errors
605
+ ### Raising validation errors
604
606
605
607
Our ` ColorField ` class above currently does not perform any data validation.
606
608
To 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
646
648
647
649
This style keeps your error messages cleaner and more separated from your code, and should be preferred.
648
650
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
+
649
720
# Third party packages
650
721
651
722
The following third party packages are also available.
0 commit comments