본문 바로가기
Python/REST Framework

[REST] Nested relationships

by 혀나Lee 2016. 10. 11.

Nested relationships[각주:1]

Nested relationsips는 serializers 자체를 serializer 필드로써 사용하는 방법이다.
만약, serializer를 리스트 파라미터로 받고 싶은 경우, 필드를 추가할 때 many=True를 추가하면 된다.

Example:

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title', 'duration')

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

위의 serializer를 사용한 예이다.
>>> album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse')
>>> Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)
<Track: Track object>
>>> Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264)
<Track: Track object>
>>> Track.objects.create(album=album, order=3, title='Encore', duration=159)
<Track: Track object>
>>> serializer = AlbumSerializer(instance=album)
>>> serializer.data
{
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
        ...
    ],
}

위의 예제는 AlbumSerializer를 사용하여 데이터를 가져오는 것을 보여주고 있다.
즉, album 객체 안에 tracks란 필드명으로 track객체들을 표현해 주고 있다.

Writable nested serializers[각주:2]

기본적으로 nested serializers는 read-only이다. 하지만, create()update()함수를 오버라이드(override)하여 write operations를 구현할 수 있다. 
class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ('order', 'title', 'duration')

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, **track_data)
        return album

>>> data = {
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
    ],
}
>>> serializer = AlbumSerializer(data=data)
>>> serializer.is_valid()
True
>>> serializer.save()
<Album: Album object>

Album 객체를 생성할 때, Track 객체 리스트를 생성하는 경우이다. AlbumSerializer()에서 create()를 override하여 Track 객체의 리스트가 등록될 수 있도록 한다.
단, 위와 같이 구현할 경우 객체를 생성할 때 필요없는 데이터는 validated_data에서 제거 후 사용해야 한다.
tracks_data = validated_data.pop('tracks') 가 tracks 키로 전달받은 파라미터를 validated_data에서 제거하면서 받는 방법이다.


  1. https://github.com/carltongibson/django-filter#django-filter [본문으로]
  2. http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers [본문으로]

댓글