【问题标题】:Django DRF serializer Custom relational fields How to build return value of to_internal_value?Django DRF 序列化程序自定义关系字段如何构建 to_internal_value 的返回值?
【发布时间】:2020-01-29 08:41:26
【问题描述】:

我正在尝试实现与 Djang Rest Framework 教程Custom relational fields 非常相似的东西。

为了提醒,提供的代码sn-p是:

import time

class TrackListingField(serializers.RelatedField):
    def to_representation(self, value):
        duration = time.strftime('%M:%S', time.gmtime(value.duration))
        return 'Track %d: %s (%s)' % (value.order, value.name, duration)

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

    class Meta:
        model = Album
        fields = ['album_name', 'artist', 'tracks']

然后“此自定义字段将序列化为以下表示”(在教程中引用):

{
    'album_name': 'Sometimes I Wish We Were an Eagle',
    'artist': 'Bill Callahan',
    'tracks': [
        'Track 1: Jim Cain (04:39)',
        'Track 2: Eid Ma Clack Shaw (04:19)',
        'Track 3: The Wind and the Dove (04:34)',
        ...
    ]
}

我了解这一点,并已针对我的特殊情况实施了它。

我不明白的是实现to_internal_value(self, data) 的方式,因为我想提供一个读写API。

我知道to_internal_value(self, data) 应该返回一个 AlbumTrack 对象,但我不明白如何构建它。特别是如何取回相册相关的id?

如果我们发布上面的 JSON 结构,to_internal_value(self, data) 将在每个轨道上调用一次,'Track 1: Jim Cain (04:39)'... 对于 data 值。 我不明白我们如何根据这些 data 值更新轨道模型。

【问题讨论】:

    标签: django django-rest-framework deserialization


    【解决方案1】:

    您似乎正在尝试实现可写的嵌套序列化程序。虽然嵌套序列化程序默认是只读的,但 DRF 有一节解释如何实现可写序列化程序:https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers

    由于您希望 TrackListingField 序列化 Track 模型,它应该继承自 ModelSerializer

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

    然后您必须为AlbumSerializer 覆盖create 方法:

        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
    

    请注意,以上内容将对每个曲目进行一次数据库查询。您可以使用Track.objects.bulk_create 进行一次查询以创建所有曲目。

    要回答您最初关于 to_internal_value 的问题,您可以通过将此 print 语句添加到覆盖的 to_internal_value 来查看默认值:

    class TrackSerializer(serializers.ModelSerializer):
        ...
        def to_internal_value(self, data):
            default_return_value = super(TrackSerializer, self).to_internal_value(data)
            print(default_return_value)
            return default_return_value
    

    对于ModelSerializer,DRF 使用OrderedDict 输出to_internal_value。您的自定义to_internal_value 必须使用正则表达式从data 字符串中提取ordernameduration,并将它们放入OrderedDict。但是在这种情况下,使用字典作为曲目的表示可能会更容易。

    【讨论】:

      猜你喜欢
      • 2017-03-10
      • 1970-01-01
      • 2017-02-04
      • 1970-01-01
      • 2021-10-28
      • 1970-01-01
      • 2016-01-28
      • 1970-01-01
      • 2019-07-12
      相关资源
      最近更新 更多