关联对象嵌套序列化

如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。

例如,在定义英雄数据的序列化器时,外键hbook(即所属的图书)字段如何序列化?

多对一

一对多

多对一的情况

我们先定义HeroInfoSerialzier除外键字段外的其他部分:

class HeroInfoSerialzier(serializers.Serializer):
    # 英雄序列化器
    hname = serializers.CharField()
    hcomment = serializers.CharField()

对于关联字段,可以采用以下几种方式:

1) PrimaryKeyRelatedField

此字段将被序列化为关联对象的主键。

hbook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)

指明字段时需要包含read_only=True或者queryset参数:

  • 包含read_only=True参数时,该字段将不能用作反序列化使用

通过

python manage.py shell

使用结果显示:

from book_drf.serializer import HeroInfoSerializer
from books.models import HeroInfo
hero = HeroInfo.objects.get(id=6)
ser = HeroInfoSerializer(hero)
ser.data
)}

2) StringRelatedField

此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)

hbook = serializers.StringRelatedField(label='图书')

使用效果

{'id': 6, 'hname': '乔峰', 'hgender': 1, 'hcomment': '降龙十八掌', 'hbook': '天龙八部'}

3)使用关联对象的序列化器

hbook = BookInfoSerializer()

使用效果

{'hname': '乔峰', 'hcomment': '降龙十八掌', 'hbook': OrderedDict([('btitle', '天龙八部'), ('bread', 36), ('bpub_date', '1986-07-24')]

完整代码如下:

from rest_framework import serializers
# 自定义序列化器
class BookSerialzier(serializers.Serializer):
    # 序列化返回字段
    btitle = serializers.CharField()
    bread = serializers.IntegerField()
    bpub_date = serializers.DateField()
    # 返回关联的英雄id   PrimaryKeyRelatedField
    # heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
    # 返回关联英雄模型类的str方法值
    # heroinfo_set = serializers.StringRelatedField(read_only=True, many=True)
    # 注意事项:内嵌的序列化器必须放在前面
    # heroinfo_set = HeroInfoSerializer(many=True)

class HeroInfoSerializer(serializers.Serializer):
    # 英雄序列化器
    hname = serializers.CharField()
    hcomment = serializers.CharField()
    # hbook=serializers.PrimaryKeyRelatedField(read_only=True)
    # hbook = serializers.StringRelatedField(label='图书')
    hbook = BookSerialzier()

单独定义的内嵌序列化器必须放在上面

HeroInfoSerializer调用BookSerialzier()所以要放在HeroInfoSerializer的上面BookSerialzier

一对多的情况

many参数

如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数即可。

此处仅拿PrimaryKeyRelatedField类型来举例,其他相同。

在BookInfoSerializer中添加关联字段:

from rest_framework import serializers

class HeroInfoSerializer(serializers.Serializer):
    # 英雄序列化器
    hname = serializers.CharField()
    hcomment = serializers.CharField()
    hbook=serializers.PrimaryKeyRelatedField(read_only=True)
    # hbook = serializers.StringRelatedField(label='图书')

# 自定义序列化器
class BookSerialzier(serializers.Serializer):
    # 序列化返回字段
    btitle = serializers.CharField()
    bread = serializers.IntegerField()
    bpub_date = serializers.DateField()
    # 返回关联的英雄id   PrimaryKeyRelatedField
    # heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
    # 返回关联英雄模型类的str方法值
    # heroinfo_set = serializers.StringRelatedField(read_only=True, many=True)
    # 注意事项:内嵌的序列化器必须放在前面
    heroinfo_set = HeroInfoSerializer(many=True)

显示的结果如下:

[
    {
        "btitle": "射雕英雄传",
        "bread": 12,
        "bpub_date": "1980-05-01",
        "heroinfo_set": [
            {
                "hname": "郭靖",
                "hcomment": "降龙十八掌",
                "hbook": 1
            },
            {
                "hname": "黄蓉",
                "hcomment": "打狗棍法",
                "hbook": 1
            },
            {
                "hname": "黄药师",
                "hcomment": "弹指神通",
                "hbook": 1
            },
            {
                "hname": "欧阳锋",
                "hcomment": "蛤蟆功",
                "hbook": 1
            },
            {
                "hname": "梅超风",
                "hcomment": "九阴白骨爪",
                "hbook": 1
            }
        ]
    },
    {
        "btitle": "天龙八部",
        "bread": 36,
        "bpub_date": "1986-07-24",
        "heroinfo_set": [
            {
                "hname": "乔峰",
                "hcomment": "降龙十八掌",
                "hbook": 2
            },
            {
                "hname": "段誉",
                "hcomment": "六脉神剑",
                "hbook": 2
            },
            {
                "hname": "虚竹",
                "hcomment": "天山六阳掌",
                "hbook": 2
            },
            {
                "hname": "王语嫣",
                "hcomment": "神仙姐姐",
                "hbook": 2
            }
        ]
    },
    {
        "btitle": "笑傲江湖",
        "bread": 20,
        "bpub_date": "1995-12-24",
        "heroinfo_set": [
            {
                "hname": "令狐冲",
                "hcomment": "独孤九剑",
                "hbook": 3
            },
            {
                "hname": "任盈盈",
                "hcomment": "弹琴",
                "hbook": 3
            },
            {
                "hname": "岳不群",
                "hcomment": "华山剑法",
                "hbook": 3
            },
            {
                "hname": "东方不败",
                "hcomment": "葵花宝典",
                "hbook": 3
            }
        ]
    },
    {
        "btitle": "雪山飞狐",
        "bread": 58,
        "bpub_date": "1987-11-11",
        "heroinfo_set": [
            {
                "hname": "胡斐",
                "hcomment": "胡家刀法",
                "hbook": 4
            },
            {
                "hname": "苗若兰",
                "hcomment": "黄衣",
                "hbook": 4
            },
            {
                "hname": "程灵素",
                "hcomment": "医术",
                "hbook": 4
            },
            {
                "hname": "袁紫衣",
                "hcomment": "六合拳",
                "hbook": 4
            }
        ]
    }
]