参考来源(rest framework 官网):api_guide-relations
前言:已经好久没有用Django了,很多东西已经忘了,所以文章中有存在不足的地方,欢迎指正。
之前用Django做了一个web项目,也不知道是公司服务器的问题,还是什么,前端拿数据的速度很慢。600多条数据,竟然最快也需要5秒,我能做的就只有优化代码了。。。
看了一下之前写的code,确实有优化的空间,现在回去看之前写的代码,感觉太low…
目的:A对象和owner是一对一关系,B对象和owner是多对多关系。页面上需要显示A对象和B对象的owner的name。但是默认的serializers 序列化之后return 的是关联对象的id,也就是说A对象的serializer.data中的owner 是id,而B对象是owner_id_list,这并不是我想要的。我需要的是owner_name。
之前的做法很low,是拿到owner_id或者owner_id_list 再根据id去查询owner_name, owner_id_list 还得循环, 这样肯定很影响速度。所以必须改。
model:
class Owner(models.Model):
name = models.CharField(max_length=20, unique=True)
objects = moldes.Manager()
class A(models.Model):
owner = models.ForeignKey('Owner', on_delete=models.CASCADE)
name = models.CharField(max_length=20)
objects = moldes.Manager()
class B(models.Model):
owner = models.MnayToManyField(Owner)
name = models.CharField(max_length=20)
objects = moldes.Manager()
默认的serializer很简单:
class OwnerSerializer(serialziers.ModelSerializer):
class Mate:
model = Owner
fields = ['id', 'name']
class ASerializer(serialziers.ModelSerializer):
class Mate:
model = A
fields = ['id', 'name', 'owner']
class BSerializer(serialziers.ModelSerializer):
class Mate:
model = B
fields = ['id', 'name', 'owner']
但是这样返回的数据中owner是以id的形式存在的,我需要返回的数据中有owner_name。
所以我需要改写serializer。(这里我既想保留owner_id,又想返回owner_name, 如ASerializer fields中,owner字段为owner_id,a_owner 为owner_name)
多对多的情况会稍微复杂一点。
重写serializer:
class OwnerSerializer(serialziers.ModelSerializer):
class Mate:
model = Owner
fields = ['id', 'name']
#一对一的情况
class ASerializer(serialziers.ModelSerializer):
a_owner = serializers.CharField(source='owner.name', read_only=True)
class Mate:
model = A
fields = ['id', 'name', 'owner', 'a_owner']
# 这里我既保留了owner(返回值为owner_id),又新增了a_owner(返回值为owner_name)
# 如果不想保留owner_id, 直接把owner的返回值由owner_id变成owner_name,可以这样:
# class ASerializer(serialziers.ModelSerializer):
# owner = serializers.CharField(read_only=True)
# 这里的owner变量必须要和A model 的owner字段名一样,否则会报错,
#因为rest_framework就是根据这个变量去找对应的字段。
#如果你的owner名字和A model中的owner字段名不一样,就必须在后面加source='owner.name',
#就像上面未注释的class ASerializer那样。
# class Mate:
# model = A
# fields = ['id', 'name', 'owner']
#多对多的情况
class BOwnerField(serializer.RelatedField):
def to_representation(self, value):
return value.name
# 按官网说的,这里可以自定义返回的格式,例如:return f'{value.id}: {value.name}',这将使得b_owner = ['1: wang', '2:zhang']。
class BSerializer(serialziers.ModelSerializer):
b_owner = BOwnerField(many=True, read_only=True, source='owner')
class Mate:
model = Owner
fields = ['id', 'name', 'owner', 'b_owner']