Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add example usingsource=‘*’ to custom field docs.#5688

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 134 additions & 1 deletiondocs/api-guide/fields.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -561,6 +561,8 @@ Note that the `WritableField` class that was present in version 2.x no longer ex

## Examples

### A Basic Custom Field

Let's look at an example of serializing a class that represents an RGB color value:

class Color(object):
Expand DownExpand Up@@ -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__

#### Raising validation errors
### Raising validation errors

Our `ColorField` class above currently does not perform any data validation.
To indicate invalid data, we should raise a `serializers.ValidationError`, like so:
Expand DownExpand Up@@ -646,6 +648,137 @@ 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.

### 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 `source='*'`, with two `IntegerField` instances, each with their own `source`
pointing to the relevant field.

The key points from the example, though, are:

* `to_representation` is passed the entire `DataPoint` object and 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)])

For completeness lets do the same thing again but with the nested serialiser
approach suggested above:

class NestedCoordinateSerializer(serializers.Serializer):
x = serializers.IntegerField(source='x_coordinate')
y = serializers.IntegerField(source='y_coordinate')


class DataPointSerializer(serializers.ModelSerializer):
coordinates = NestedCoordinateSerializer(source='*')

class Meta:
model = DataPoint
fields = ['label', 'coordinates']

Here the mapping between the target and source attribute pairs (`x` and
`x_coordinate`, `y` and `y_coordinate`) is handled in the `IntegerField`
declarations. It's our `NestedCoordinateSerializer` that takes `source='*'`.

Our new `DataPointSerializer` exhibits the same behaviour as the custom field
approach.

Serialising:

>>> out_serializer = DataPointSerializer(instance)
>>> out_serializer.data
ReturnDict([('label', 'testing'),
('coordinates', OrderedDict([('x', 1), ('y', 2)]))])

Deserialising:

>>> in_serializer = DataPointSerializer(data=data)
>>> in_serializer.is_valid()
True
>>> in_serializer.validated_data
OrderedDict([('label', 'still testing'),
('x_coordinate', 3),
('y_coordinate', 4)])

But we also get the built-in validation for free:

>>> invalid_data = {
... "label": "still testing",
... "coordinates": {
... "x": 'a',
... "y": 'b',
... }
... }
>>> invalid_serializer = DataPointSerializer(data=invalid_data)
>>> invalid_serializer.is_valid()
False
>>> invalid_serializer.errors
ReturnDict([('coordinates',
{'x': ['A valid integer is required.'],
'y': ['A valid integer is required.']})])

For this reason, the nested serialiser approach would be the first to try. You
would use the custom field approach when the nested serialiser becomes infeasible
or overly complex.


# Third party packages

The following third party packages are also available.
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp