mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-04 12:30:11 +03:00
Add example using source=‘*’
to custom field docs.
Closes #2032 closes #3066
This commit is contained in:
parent
ea0b3b32ad
commit
397a89c060
|
@ -561,6 +561,8 @@ Note that the `WritableField` class that was present in version 2.x no longer ex
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
### A Basic Custom Field
|
||||||
|
|
||||||
Let's look at an example of serializing a class that represents an RGB color value:
|
Let's look at an example of serializing a class that represents an RGB color value:
|
||||||
|
|
||||||
class Color(object):
|
class Color(object):
|
||||||
|
@ -600,7 +602,7 @@ As an example, let's create a field that can be used to represent the class name
|
||||||
"""
|
"""
|
||||||
return obj.__class__.__name__
|
return obj.__class__.__name__
|
||||||
|
|
||||||
#### Raising validation errors
|
### Raising validation errors
|
||||||
|
|
||||||
Our `ColorField` class above currently does not perform any data validation.
|
Our `ColorField` class above currently does not perform any data validation.
|
||||||
To indicate invalid data, we should raise a `serializers.ValidationError`, like so:
|
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
|
||||||
|
|
||||||
This style keeps your error messages cleaner and more separated from your code, and should be preferred.
|
This style keeps your error messages cleaner and more separated from your code, and should be preferred.
|
||||||
|
|
||||||
|
### Using `source='*'`
|
||||||
|
|
||||||
|
Here we'll take an example of a _flat_ `DataPoint` model with `x_coordinate` and `y_coordinate` attributes.
|
||||||
|
|
||||||
|
class DataPoint(models.Model):
|
||||||
|
label = models.CharField(max_length=50)
|
||||||
|
x_coordinate = models.SmallIntegerField()
|
||||||
|
y_coordinate = models.SmallIntegerField()
|
||||||
|
|
||||||
|
Using a custom field and `source='*'` we can provide a nested representation of
|
||||||
|
the coordinate pair:
|
||||||
|
|
||||||
|
class CoordinateField(serializers.Field):
|
||||||
|
|
||||||
|
def to_representation(self, obj):
|
||||||
|
ret = {
|
||||||
|
"x": obj.x_coordinate,
|
||||||
|
"y": obj.y_coordinate
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
ret = {
|
||||||
|
"x_coordinate": data["x"],
|
||||||
|
"y_coordinate": data["y"],
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class DataPointSerializer(serializers.ModelSerializer):
|
||||||
|
coordinates = CoordinateField(source='*')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = DataPoint
|
||||||
|
fields = ['label', 'coordinates']
|
||||||
|
|
||||||
|
Note that this example doesn't handle validation. Partly for that reason, in a
|
||||||
|
real project, the coordinate nesting might be better handled with a nested serialiser using two
|
||||||
|
`IntegerField` instances, each with `source='*'`.
|
||||||
|
|
||||||
|
The key points from the example, though, are:
|
||||||
|
|
||||||
|
* `to_representation` is passed the entire `DataPoint` object must map from that
|
||||||
|
to the desired output.
|
||||||
|
|
||||||
|
>>> instance = DataPoint(label='Example', x_coordinate=1, y_coordinate=2)
|
||||||
|
>>> out_serializer = DataPointSerializer(instance)
|
||||||
|
>>> out_serializer.data
|
||||||
|
ReturnDict([('label', 'testing'), ('coordinates', {'x': 1, 'y': 2})])
|
||||||
|
|
||||||
|
* Unless our field is to be read-only, `to_internal_value` must map back to a dict
|
||||||
|
suitable for updating our target object. With `source='*'`, the return from
|
||||||
|
`to_internal_value` will update the root validated data dictionary, rather than a single key.
|
||||||
|
|
||||||
|
>>> data = {
|
||||||
|
... "label": "Second Example",
|
||||||
|
... "coordinates": {
|
||||||
|
... "x": 3,
|
||||||
|
... "y": 4,
|
||||||
|
... }
|
||||||
|
... }
|
||||||
|
>>> in_serializer = DataPointSerializer(data=data)
|
||||||
|
>>> in_serializer.is_valid()
|
||||||
|
True
|
||||||
|
>>> in_serializer.validated_data
|
||||||
|
OrderedDict([('label', 'Second Example'),
|
||||||
|
('y_coordinate', 4),
|
||||||
|
('x_coordinate', 3)])
|
||||||
|
|
||||||
# Third party packages
|
# Third party packages
|
||||||
|
|
||||||
The following third party packages are also available.
|
The following third party packages are also available.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user