1. 程式人生 > 其它 >Djando REST Framework 序列化返回關聯物件除id之外的欄位

Djando REST Framework 序列化返回關聯物件除id之外的欄位

技術標籤:Django rest frameworkserializerrelationsdjangopython

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']