You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在DRF中扁平化嵌套Serializer?

在Django REST Framework中扁平化嵌套Serializer的实现方法

问题背景

需要将DRF中嵌套的Serializer输出扁平化,但官方文档里没找到现成实现方法。

当前输出

{
    "user_inventory": "UOHvaxFa11R5Z0bPYuihP0RKocn2",
    "quantity": 1,
    "player": {
        "card_id": "c69c0808328fdc3e3f3ee8b9b7d4a7f8",
        "game": "MLB The Show 22",
        "name": "Jesus Tinoco",
        "all_positions": [
            "CP"
        ]
    }
}

期望输出

{
    "user_inventory": "UOHvaxFa11R5Z0bPYuihP0RKocn2",
    "quantity": 1,
    "card_id": "c69c0808328fdc3e3f3ee8b9b7d4a7f8",
    "game": "MLB The Show 22",
    "name": "Jesus Tinoco",
    "all_positions": [
        "CP"
    ]
}

现有代码

序列化器定义

class PlayerProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = PlayerProfile
        fields = (
            'card_id',
            'game',
            'name',
            'all_positions',
        )

class UserInventoryItemSerializer(serializers.ModelSerializer):
    player = PlayerProfileSerializer()
    class Meta:
        model = UserInventoryItem
        fields = (
            'user_inventory',
            'quantity',
            'player',
        )

视图代码

class OwnedInventoryView(viewsets.ModelViewSet):
    serializer_class = UserInventoryItemSerializer
    filterset_class = UserInventoryItemFilter

    def get_queryset(self):
        order_by = self.request.query_params.get('order_by', '')

        if order_by:
            order_by_name = order_by.split(' ')[1]
            order_by_sign = order_by.split(' ')[0]
            order_by_sign = '' if order_by_sign == 'asc' else '-'
            return UserInventoryItem.objects.filter(user_inventory=self.kwargs['user_inventory_pk']).order_by(order_by_sign + order_by_name)

        return UserInventoryItem.objects.filter(user_inventory=self.kwargs['user_inventory_pk'])

解决方案

方法1:直接用source参数映射字段

这是最直接的方式,无需嵌套Serializer,直接通过外键关联映射PlayerProfile的字段:

class UserInventoryItemSerializer(serializers.ModelSerializer):
    card_id = serializers.CharField(source='player.card_id')
    game = serializers.CharField(source='player.game')
    name = serializers.CharField(source='player.name')
    all_positions = serializers.ListField(source='player.all_positions')

    class Meta:
        model = UserInventoryItem
        fields = (
            'user_inventory',
            'quantity',
            'card_id',
            'game',
            'name',
            'all_positions',
        )

注意要根据PlayerProfile中字段的实际类型选择对应Serializer字段,比如all_positions如果是数组类型用ListField,其他类型按需调整即可。

方法2:重写to_representation方法

如果PlayerProfile字段较多,手动映射麻烦,可重写序列化器的to_representation方法自动展开嵌套字段:

class UserInventoryItemSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserInventoryItem
        fields = (
            'user_inventory',
            'quantity',
        )

    def to_representation(self, instance):
        # 获取基础序列化数据
        data = super().to_representation(instance)
        # 序列化player对象并合并到根数据
        player_data = PlayerProfileSerializer(instance.player).data
        data.update(player_data)
        return data

这种方式更灵活,自动适配PlayerProfile的字段变化。如果需要支持反序列化(比如创建/更新操作),可以保留player = PlayerProfileSerializer()的定义,或在to_internal_value方法中处理反序列化逻辑。

方法3:使用SerializerMethodField(适合需额外处理的字段)

如果仅需展开部分字段,且要对字段做自定义处理,可使用SerializerMethodField:

class UserInventoryItemSerializer(serializers.ModelSerializer):
    card_id = serializers.SerializerMethodField()
    game = serializers.SerializerMethodField()
    name = serializers.SerializerMethodField()
    all_positions = serializers.SerializerMethodField()

    class Meta:
        model = UserInventoryItem
        fields = (
            'user_inventory',
            'quantity',
            'card_id',
            'game',
            'name',
            'all_positions',
        )

    def get_card_id(self, obj):
        return obj.player.card_id

    def get_game(self, obj):
        return obj.player.game

    def get_name(self, obj):
        return obj.player.name

    def get_all_positions(self, obj):
        return obj.player.all_positions

每个字段对应一个get_xxx方法,可在方法内添加字段格式化、过滤等额外逻辑。

内容的提问来源于stack exchange,提问作者JeremyE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 05:01:19