DRF使用嵌套的序列化程序创建键对象而不是数组

时间:2019-07-01 13:40:37

标签: python-3.x django-rest-framework django-serializer

上下文

假设我们以DRF relations guide为例。

# models.py
class Album(models.Model):
    album_name = models.CharField(max_length=100)
    artist = models.CharField(max_length=100)

class Track(models.Model):
    album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
    order = models.IntegerField()
    title = models.CharField(max_length=100)
    duration = models.IntegerField()

    class Meta:
        unique_together = ('album', 'order')
        ordering = ['order']

    def __str__(self):
        return '%d: %s' % (self.order, self.title)

使用序列化程序将获得此输出

class AlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.StringRelatedField(many=True)

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

将为我们提供以下输出:

{
    'album_name': 'Things We Lost In The Fire',
    'artist': 'Low',
    'tracks': [
        '1: Sunflower',
        '2: Whitetail',
        '3: Dinosaur Act',
        ...
    ]
}

问题

我如何使用序列化器获取如下输出:

  {
    'album_name': 'Things We Lost In The Fire',
    'artist': 'Low',
    'tracks': {
        1: {order: 1, title: 'Sunflower'},
        2: {order:2, title: 'Whitetail'},
        3: {order:3, title: 'Dinosaur Act'},
        ...
    }
}

这样,我们就有了一个带有轨迹的对象,而不是一个数字数组。因此,我可以执行this.props.album.tracks[2].title来代替javascript中的this.props.album.tracks.find(track => track.order == 2}).title

``我有一个用例,在Reactjs中这似乎更方便。

我尝试过的

我考虑过重写to_representation方法。但是我看到这将使我得到一个递归循环。

class TrackSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        print(self)
        return '%s: { %s }' % (instance.order, self.to_representation(instance))
    class Meta:
        fields = '__all__'
        model = Track

此外,我已经搜索并很好地阅读了文档。但是,对于我认为开箱即用的合理解决方案,没有找到任何解决方案。让我以为我错了,错过了什么。

先谢谢了。

1 个答案:

答案 0 :(得分:0)

定义新的 TrackSerializer ,并在 AlbumSerializer 类中将其用作


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


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

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

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        representation['tracks'] = {track['id']: track for track in representation['tracks']}
        return representation