mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-08 06:14:47 +03:00
Merge 9fd838e556
into 209bcb9087
This commit is contained in:
commit
9cb0ee7df9
|
@ -238,7 +238,7 @@ Nested relationships can be expressed by using serializers as fields.
|
||||||
|
|
||||||
If the field is used to represent a to-many relationship, you should add the `many=True` flag to the serializer field.
|
If the field is used to represent a to-many relationship, you should add the `many=True` flag to the serializer field.
|
||||||
|
|
||||||
## Example
|
## Read-only example
|
||||||
|
|
||||||
For example, the following serializer:
|
For example, the following serializer:
|
||||||
|
|
||||||
|
@ -256,6 +256,15 @@ For example, the following serializer:
|
||||||
|
|
||||||
Would serialize to a nested representation like this:
|
Would serialize to a nested representation like this:
|
||||||
|
|
||||||
|
>>> album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse')
|
||||||
|
>>> Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=0)
|
||||||
|
<Track: Track object>
|
||||||
|
>>> Track.objects.create(album=album, order=2, title='What More Can I Say', duration=0)
|
||||||
|
<Track: Track object>
|
||||||
|
>>> Track.objects.create(album=album, order=3, title='Encore', duration=0)
|
||||||
|
<Track: Track object>
|
||||||
|
>>> serializer = AlbumSerializer(instance=album)
|
||||||
|
>>> serializer.data
|
||||||
{
|
{
|
||||||
'album_name': 'The Grey Album',
|
'album_name': 'The Grey Album',
|
||||||
'artist': 'Danger Mouse',
|
'artist': 'Danger Mouse',
|
||||||
|
@ -263,10 +272,52 @@ Would serialize to a nested representation like this:
|
||||||
{'order': 1, 'title': 'Public Service Announcement'},
|
{'order': 1, 'title': 'Public Service Announcement'},
|
||||||
{'order': 2, 'title': 'What More Can I Say'},
|
{'order': 2, 'title': 'What More Can I Say'},
|
||||||
{'order': 3, 'title': 'Encore'},
|
{'order': 3, 'title': 'Encore'},
|
||||||
...
|
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Writable nested serializers
|
||||||
|
|
||||||
|
To use writable nested serialization you'll want to declare a nested field on
|
||||||
|
the serializer class, and write the `create(validated_data)` and/or
|
||||||
|
`update(instance, validated_data)` methods explicitly.
|
||||||
|
Note that nested serializers also works for regular serializers.
|
||||||
|
|
||||||
|
class TrackSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Track
|
||||||
|
fields = ('order', 'title')
|
||||||
|
|
||||||
|
class AlbumSerializer(serializers.ModelSerializer):
|
||||||
|
tracks = TrackSerializer(many=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Album
|
||||||
|
fields = ('album_name', 'artist', 'tracks')
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
tracks_data = validated_data.pop('tracks')
|
||||||
|
album = Album.objects.create(**validated_data)
|
||||||
|
for track_data in tracks_data:
|
||||||
|
Track.objects.create(album=album, duration=0, **track_data)
|
||||||
|
return album
|
||||||
|
|
||||||
|
>>> data = {
|
||||||
|
'album_name': 'The Grey Album',
|
||||||
|
'artist': 'Danger Mouse',
|
||||||
|
'tracks': [
|
||||||
|
{'order': 1, 'title': 'Public Service Announcement'},
|
||||||
|
{'order': 2, 'title': 'What More Can I Say'},
|
||||||
|
{'order': 3, 'title': 'Encore'},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
>>> serializer = AlbumSerializer(data=data)
|
||||||
|
>>> serializer.is_valid()
|
||||||
|
True
|
||||||
|
>>> serializer.save()
|
||||||
|
<Album: Album object>
|
||||||
|
>>>
|
||||||
|
|
||||||
|
|
||||||
# Custom relational fields
|
# Custom relational fields
|
||||||
|
|
||||||
To implement a custom relational field, you should override `RelatedField`, and implement the `.to_representation(self, value)` method. This method takes the target of the field as the `value` argument, and should return the representation that should be used to serialize the target. The `value` argument will typically be a model instance.
|
To implement a custom relational field, you should override `RelatedField`, and implement the `.to_representation(self, value)` method. This method takes the target of the field as the `value` argument, and should return the representation that should be used to serialize the target. The `value` argument will typically be a model instance.
|
||||||
|
|
|
@ -296,19 +296,26 @@ Similarly, the `.validated_data` property will include nested data structures.
|
||||||
If you're supporting writable nested representations you'll need to write `.create()` or `.update()` methods that handle saving multiple objects.
|
If you're supporting writable nested representations you'll need to write `.create()` or `.update()` methods that handle saving multiple objects.
|
||||||
|
|
||||||
The following example demonstrates how you might handle creating a user with a nested profile object.
|
The following example demonstrates how you might handle creating a user with a nested profile object.
|
||||||
|
Please note that though we're using Django's Models it could be any Python class as well.
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
|
||||||
profile = ProfileSerializer()
|
|
||||||
|
|
||||||
class Meta:
|
class CommentSerializer(serializers.Serializer):
|
||||||
model = User
|
user = UserSerializer(required=False) # May be an anonymous user.
|
||||||
fields = ('username', 'email', 'profile')
|
content = serializers.CharField(max_length=200)
|
||||||
|
created = serializers.DateTimeField()
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
profile_data = validated_data.pop('profile')
|
# Get or create the user if provided
|
||||||
user = User.objects.create(**validated_data)
|
user = None
|
||||||
Profile.objects.create(user=user, **profile_data)
|
user_data = validated_data.pop('user')
|
||||||
return user
|
if user_data:
|
||||||
|
user = User.objects.get_or_create(**user_data)
|
||||||
|
|
||||||
|
# Create the comment
|
||||||
|
comment = Comment.objects.create(user=user, **validated_data)
|
||||||
|
|
||||||
|
return comment
|
||||||
|
|
||||||
|
|
||||||
#### Writing `.update()` methods for nested representations
|
#### Writing `.update()` methods for nested representations
|
||||||
|
|
||||||
|
@ -319,9 +326,10 @@ For updates you'll want to think carefully about how to handle updates to relati
|
||||||
* Ignore the data and leave the instance as it is.
|
* Ignore the data and leave the instance as it is.
|
||||||
* Raise a validation error.
|
* Raise a validation error.
|
||||||
|
|
||||||
Here's an example for an `update()` method on our previous `UserSerializer` class.
|
Here's an example for an `update()` method on our previous `CommentSerializer` class.
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
|
|
||||||
profile_data = validated_data.pop('profile')
|
profile_data = validated_data.pop('profile')
|
||||||
# Unless the application properly enforces that this field is
|
# Unless the application properly enforces that this field is
|
||||||
# always set, the follow could raise a `DoesNotExist`, which
|
# always set, the follow could raise a `DoesNotExist`, which
|
||||||
|
|
Loading…
Reference in New Issue
Block a user