关联对象嵌套序列化
如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。
例如,在定义英雄数据的序列化器时,外键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
}
]
}
]