diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 33db82ee1..fa5ac1431 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -403,7 +403,7 @@ class BaseSerializer(WritableField): return # Set the serializer object if it exists - obj = getattr(self.parent.object, field_name) if self.parent.object else None + obj = get_component(self.parent.object, self.source or field_name) if self.parent.object else None obj = obj.all() if is_simple_callable(getattr(obj, 'all', None)) else obj if self.source == '*': diff --git a/rest_framework/tests/test_serializer_nested.py b/rest_framework/tests/test_serializer_nested.py index 71d0e24b5..e454235a1 100644 --- a/rest_framework/tests/test_serializer_nested.py +++ b/rest_framework/tests/test_serializer_nested.py @@ -244,3 +244,70 @@ class WritableNestedSerializerObjectTests(TestCase): serializer = self.AlbumSerializer(data=data, many=True) self.assertEqual(serializer.is_valid(), True) self.assertEqual(serializer.object, expected_object) + + +class ForeignKeyNestedSerializerUpdateTests(TestCase): + def setUp(self): + class Artist(object): + def __init__(self, name): + self.name = name + + def __eq__(self, other): + return self.name == other.name + + class Album(object): + def __init__(self, name, artist): + self.name, self.artist = name, artist + + def __eq__(self, other): + return self.name == other.name and self.artist == other.artist + + class ArtistSerializer(serializers.Serializer): + name = serializers.CharField() + + def restore_object(self, attrs, instance=None): + if instance: + instance.name = attrs['name'] + else: + instance = Artist(attrs['name']) + return instance + + class AlbumSerializer(serializers.Serializer): + name = serializers.CharField() + by = ArtistSerializer(source='artist') + + def restore_object(self, attrs, instance=None): + if instance: + instance.name = attrs['name'] + instance.artist = attrs['artist'] + else: + instance = Album(attrs['name'], attrs['artist']) + return instance + + self.Artist = Artist + self.Album = Album + self.AlbumSerializer = AlbumSerializer + + def test_create_via_foreign_key_with_source(self): + """ + Check that we can both *create* and *update* into objects across + ForeignKeys that have a `source` specified. + Regression test for # + """ + data = { + 'name': 'Discovery', + 'by': {'name': 'Daft Punk'}, + } + + expected = self.Album(artist=self.Artist('Daft Punk'), name='Discovery') + + # create + serializer = self.AlbumSerializer(data=data) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(serializer.object, expected) + + # update + original = self.Album(artist=self.Artist('The Bats'), name='Free All the Monsters') + serializer = self.AlbumSerializer(instance=original, data=data) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(serializer.object, expected)