mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-04 12:30:11 +03:00
Merge 585c906faa
into d34dfc3fac
This commit is contained in:
commit
344151e649
|
@ -434,7 +434,7 @@ class BaseSerializer(WritableField):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if self.default is not None and not self.partial:
|
if self.default is not None and not self.partial:
|
||||||
# Note: partial updates shouldn't set defaults
|
# Note: partial updates shouldn't set defaults
|
||||||
value = copy.deepcopy(self.default)
|
value = copy.deepcopy(self.get_default_value())
|
||||||
else:
|
else:
|
||||||
if self.required:
|
if self.required:
|
||||||
raise ValidationError(self.error_messages['required'])
|
raise ValidationError(self.error_messages['required'])
|
||||||
|
|
|
@ -247,6 +247,136 @@ class WritableNestedSerializerObjectTests(TestCase):
|
||||||
self.assertEqual(serializer.object, expected_object)
|
self.assertEqual(serializer.object, expected_object)
|
||||||
|
|
||||||
|
|
||||||
|
class WritableNestedSerializerWithDefaultValueTests(TestCase):
|
||||||
|
"""
|
||||||
|
Tests for deserializing nested entities with default values.
|
||||||
|
These tests use serializers that restore to concrete objects.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Couple of concrete objects that we're going to deserialize into
|
||||||
|
class Artist(object):
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.name == other.name
|
||||||
|
|
||||||
|
class Track(object):
|
||||||
|
def __init__(self, order, title, duration):
|
||||||
|
self.order, self.title, self.duration = order, title, duration
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (
|
||||||
|
self.order == other.order and
|
||||||
|
self.title == other.title and
|
||||||
|
self.duration == other.duration
|
||||||
|
)
|
||||||
|
|
||||||
|
class Album(object):
|
||||||
|
def __init__(self, album_name, artist, tracks):
|
||||||
|
self.album_name, self.artist, self.tracks = album_name, artist, tracks
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (
|
||||||
|
self.album_name == other.album_name and
|
||||||
|
self.artist == other.artist and
|
||||||
|
self.tracks == other.tracks
|
||||||
|
)
|
||||||
|
|
||||||
|
# And their corresponding serializers
|
||||||
|
class ArtistSerializer(serializers.Serializer):
|
||||||
|
name = serializers.CharField(max_length=100)
|
||||||
|
|
||||||
|
def restore_object(self, attrs, instance=None):
|
||||||
|
return Artist(attrs['name'])
|
||||||
|
|
||||||
|
class TrackSerializer(serializers.Serializer):
|
||||||
|
order = serializers.IntegerField()
|
||||||
|
title = serializers.CharField(max_length=100)
|
||||||
|
duration = serializers.IntegerField()
|
||||||
|
|
||||||
|
def restore_object(self, attrs, instance=None):
|
||||||
|
return Track(attrs['order'], attrs['title'], attrs['duration'])
|
||||||
|
|
||||||
|
class AlbumSerializer(serializers.Serializer):
|
||||||
|
album_name = serializers.CharField(max_length=100)
|
||||||
|
artist = ArtistSerializer(
|
||||||
|
required=False,
|
||||||
|
default={'name': 'Unknown'}
|
||||||
|
)
|
||||||
|
tracks = TrackSerializer(
|
||||||
|
many=True,
|
||||||
|
required=False,
|
||||||
|
default=lambda: [{'order': 1, 'title': 'Untitled', 'duration': 0}]
|
||||||
|
)
|
||||||
|
|
||||||
|
def restore_object(self, attrs, instance=None):
|
||||||
|
return Album(attrs['album_name'], attrs['artist'], attrs['tracks'])
|
||||||
|
|
||||||
|
self.Album, self.Track, self.Artist = Album, Track, Artist
|
||||||
|
self.AlbumSerializer = AlbumSerializer
|
||||||
|
|
||||||
|
def test_nested_serializer_with_non_callable_default_value(self):
|
||||||
|
"""
|
||||||
|
Correct nested serialization should return a restored object
|
||||||
|
that corresponds to the input data, with default values used
|
||||||
|
when no input value is supplied.
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'album_name': 'Discovery',
|
||||||
|
'tracks': [
|
||||||
|
{'order': 1, 'title': 'One More Time', 'duration': 235},
|
||||||
|
{'order': 2, 'title': 'Aerodynamic', 'duration': 184},
|
||||||
|
{'order': 3, 'title': 'Digital Love', 'duration': 239}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
expected_object = self.Album(
|
||||||
|
album_name='Discovery',
|
||||||
|
artist=self.Artist(name='Unknown'),
|
||||||
|
tracks=[
|
||||||
|
self.Track(order=1, title='One More Time', duration=235),
|
||||||
|
self.Track(order=2, title='Aerodynamic', duration=184),
|
||||||
|
self.Track(order=3, title='Digital Love', duration=239),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
serializer = self.AlbumSerializer(data=data)
|
||||||
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
|
self.assertEqual(serializer.object, expected_object)
|
||||||
|
|
||||||
|
def test_nested_serializer_with_callable_default_value(self):
|
||||||
|
"""
|
||||||
|
Correct nested serialization should return a restored object
|
||||||
|
that corresponds to the input data, with default values used
|
||||||
|
when no input value is supplied. If the default value is callable,
|
||||||
|
it should be evaluated each time the serializer is used.
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'album_name': 'Discovery',
|
||||||
|
'artist': {'name': 'Daft Punk'}
|
||||||
|
}
|
||||||
|
expected_object = self.Album(
|
||||||
|
album_name='Discovery',
|
||||||
|
artist=self.Artist(name='Daft Punk'),
|
||||||
|
tracks=[
|
||||||
|
self.Track(order=1, title='Untitled', duration=0),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
serializer = self.AlbumSerializer(data=data)
|
||||||
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
|
self.assertEqual(serializer.object, expected_object)
|
||||||
|
|
||||||
|
# Using the serializer again should re-evaluate the default value
|
||||||
|
serializer = self.AlbumSerializer(data=data)
|
||||||
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
|
self.assertEqual(serializer.object, expected_object)
|
||||||
|
self.assertIsNot(serializer.object.tracks, expected_object.tracks)
|
||||||
|
|
||||||
|
|
||||||
class ForeignKeyNestedSerializerUpdateTests(TestCase):
|
class ForeignKeyNestedSerializerUpdateTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
class Artist(object):
|
class Artist(object):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user