Djando REST Framework 序列化返回关联对象除id之外的字段

危砚
2023-12-01

Djando REST Framework 序列化返回关联对象除id之外的字段

参考来源(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']
 类似资料: