如何在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
相关产品推荐
相关产品推荐

