Skip to content

Commit 5d40079

Browse files
committed
Add nested serialiser example
1 parent b06c8f2 commit 5d40079

File tree

1 file changed

+64
-2
lines changed

1 file changed

+64
-2
lines changed

docs/api-guide/fields.md

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,9 @@ the coordinate pair:
685685
fields = ['label', 'coordinates']
686686

687687
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='*'`.
688+
real project, the coordinate nesting might be better handled with a nested serialiser
689+
using `source='*'`, with two `IntegerField` instances, each with their own `source`
690+
pointing to the relevant field.
690691

691692
The key points from the example, though, are:
692693

@@ -717,6 +718,67 @@ suitable for updating our target object. With `source='*'`, the return from
717718
('y_coordinate', 4),
718719
('x_coordinate', 3)])
719720

721+
For completeness lets do the same thing again but with the nested serialiser
722+
approach suggested above:
723+
724+
class NestedCoordinateSerializer(serializers.Serializer):
725+
x = serializers.IntegerField(source='x_coordinate')
726+
y = serializers.IntegerField(source='y_coordinate')
727+
728+
729+
class DataPointSerializer(serializers.ModelSerializer):
730+
coordinates = NestedCoordinateSerializer(source='*')
731+
732+
class Meta:
733+
model = DataPoint
734+
fields = ['label', 'coordinates']
735+
736+
Here the mapping between the target and source attribute pairs (`x` and
737+
`x_coordinate`, `y` and `y_coordinate`) is handled in the `IntegerField`
738+
declarations. It's our `NestedCoordinateSerializer` that takes `source='*'`.
739+
740+
Our new `DataPointSerializer` exhibits the same behaviour as the custom field
741+
approach.
742+
743+
Serialising:
744+
745+
>>> out_serializer = DataPointSerializer(instance)
746+
>>> out_serializer.data
747+
ReturnDict([('label', 'testing'),
748+
('coordinates', OrderedDict([('x', 1), ('y', 2)]))])
749+
750+
Deserialising:
751+
752+
>>> in_serializer = DataPointSerializer(data=data)
753+
>>> in_serializer.is_valid()
754+
True
755+
>>> in_serializer.validated_data
756+
OrderedDict([('label', 'still testing'),
757+
('x_coordinate', 3),
758+
('y_coordinate', 4)])
759+
760+
But we also get the built-in validation for free:
761+
762+
>>> invalid_data = {
763+
... "label": "still testing",
764+
... "coordinates": {
765+
... "x": 'a',
766+
... "y": 'b',
767+
... }
768+
... }
769+
>>> invalid_serializer = DataPointSerializer(data=invalid_data)
770+
>>> invalid_serializer.is_valid()
771+
False
772+
>>> invalid_serializer.errors
773+
ReturnDict([('coordinates',
774+
{'x': ['A valid integer is required.'],
775+
'y': ['A valid integer is required.']})])
776+
777+
For this reason, the nested serialiser approach would be the first to try. You
778+
would use the custom field approach when the nested serialiser becomes infeasible
779+
or overly complex.
780+
781+
720782
# Third party packages
721783

722784
The following third party packages are also available.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy