一、進一步封裝優(yōu)化序列化器
- 注意:更高一級的封裝姻政,代表著更少的代碼呆抑,也代表著更低的可定制型
- 要講訴的方法,類似
Django
原生的ModelForm
對model
的引用
二汁展、ModelSerializer
類
-
ModelSerializer
類能夠讓我們自動你創(chuàng)建一個具有對應模型類中鹊碍,相對應字段的Serializer
類 -
ModelSerializer
類直接繼承了Serializer
類,不同的是:
1.它根據(jù)model模型的定義食绿,自動生成默認字段侈咕。
2.它自動生成序列化器的驗證器,比如unique_together
驗證器器紧。
3.它實現(xiàn)了簡單的.create()
方法和.update()
方法耀销。 - 聲明一個
ModelSerializer
類,(用之前寫好的序列化器示例铲汪,注釋之前的類屬性字段树姨,修改成ModelSerializer
類)
class UserSerializer(serializers.ModelSerializer):
class Meta:
# 需要序列化的model類
model = User
# 序列化所有的字段
# fields = '__all__'
# 序列化指定字段
# fields = ('name', 'password', 'email', 'sex')
# 排除哪些字段不進行序列化
exclude = ('email',)
注意:由于對應了model
類的字段,會存在必填字段桥状,所以fileds=__all__
和exclude
慎重使用
-
進入shell查看
ModelSerializer
類自動創(chuàng)建了哪些字段和驗證器(fileds=__all__
的)
進入shell -
測試是否能添加成功:
添加成功
2.1帽揪、明確指定字段
當覺得全自動的字段不滿足需求時,可以通過在ModelSerializer
類上顯式聲明字段辅斟,從而增加額外的字段或者重寫默認的字段转晰,就和在Serializer
類一樣的。
比如:
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='創(chuàng)建時間', help_text='創(chuàng)建時間', read_only=True)
class Meta:
model = User
fields = '__all__'
2.2士飒、指定只讀字段
當我們希望批量將某些字段指定為只讀查邢,而不是顯式的逐一為每個字段添加read_only=True
屬性,這種情況就可以使用Meta
的read_only_fields
選項酵幕。
該選項的值是字段名稱所組成的列表或元組扰藕,并像下面這樣聲明:
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='創(chuàng)建時間', help_text='創(chuàng)建時間', read_only=True)
class Meta:
model = User
fields = '__all__'
read_only_fields = ('sex', 'password')
注意: 有一種特殊情況,其中一個只讀字段是模型級別unique_together
約束的一部分芳撒。在這種情況下邓深,序列化器需要該字段的值才能驗證約束,但也是不能由用戶編輯的笔刹。
處理此問題的正確方法是在序列化器上顯式指定該字段芥备,同時提供read_only=True和default=…
關鍵字參數(shù)。
這種情況的一個例子就是對于一個和其他標識符unique_together
的當前認證的User
是只讀的舌菜。 在這種情況下可以像下面這樣聲明user
字段:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
-
PrimaryKeyRelatedField
處理反向關聯(lián)關系/反向序列化
比如說interfaces是projects的從表萌壳。此時的設計是:在創(chuàng)建interface時,前端會傳遞一個project_id
,我們實際在創(chuàng)建interface時袱瓮,是不會使用project_id
缤骨,project_id
在interfaces.model
和projects.model
是一個反向關聯(lián)關系。所以我們此時需要為它添加一個顯示字段尺借。
interfaces/serialzers.py
from rest_framework import serializers
from projects.models import Projects
from interfaces.models import Interfaces
class InterfaceModelSerializer(serializers.ModelSerializer):
# 從表指定輸出主表外鍵輸出的值
project = serializers.StringRelatedField(label='所屬項目', read_only=True)
# 新增model不存在的字段绊起,前端傳遞的是project_id,并且和project表是一個反向關聯(lián)關系褐望,所以需要添加一個顯示字段
project_id = serializers.PrimaryKeyRelatedField(queryset=Projects.objects.all(), write_only=True,
label='所屬項目id', help_text='所屬項目id')
class Meta:
model = Interfaces
fields = ('id', 'name', 'tester', 'create_time', 'desc', 'project', 'project_id')
extra_kwargs = {
'create_time': {
'read_only': True
}
}
def create(self, validated_data):
"""
前端傳的是project_id勒庄,而對應的字段應該是project,所以需要處理下這里
:param validated_data:
:return:
"""
project_id = validated_data.pop('project_id')
validated_data['project'] = project_id
interface_obj = super().create(validated_data)
return interface_obj
2.3瘫里、添加關鍵字參數(shù)
可以通過使用extra_kwargs
選項快捷地在字段上指定任意附加的關鍵字參數(shù)实蔽。這個選項是一個將具體字段名稱當作鍵值的字典。
- 用法:在給字段添加
ModelSerializer
無法自動添加的額外條件時使用 - 注意:
extra_kwargs
的值是一個字段谨读,里面的key需要和校驗參數(shù)一致局装,否則出錯(可看源碼)
例如:
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='創(chuàng)建時間', help_text='創(chuàng)建時間', read_only=True)
class Meta:
model = User
fields = '__all__'
extra_kwargs = {
# model的任意字段
"name": {
"write_only": True, # 字段名別寫錯
"error_messages": { # 字段名別寫錯
"max_length": "用戶名最多不能超過50個字符"
}
}
}
2.4、添加序列化器自定義的校驗
- 直接復制粘貼過來劳殖,但是要注意铐尚,必須和
class Meta
平級
class UserSerializer(serializers.ModelSerializer):
c_time = serializers.DateTimeField(label='創(chuàng)建時間', help_text='創(chuàng)建時間', read_only=True)
class Meta:
model = User
fields = '__all__'
extra_kwargs = {
# model的任意字段
"name": {
"write_only": True, # 字段名別寫錯
"error_messages": { # 字段名別寫錯
"max_length": "用戶名最多不能超過50個字符"
}
}
}
# 自定義字段級別的驗證
def validate_name(self, value):
"""
用戶名需要以“用戶”開頭
:return:
"""
if not str(value).startswith('用戶'):
# 拋出erializers.ValidationError異常
raise serializers.ValidationError(detail='用戶名需要以用戶兩個字開頭')
# 返回一個驗證過的數(shù)據(jù)
else:
return attrs
# 自定義多個字段的組合驗證規(guī)則
def validate(self, attrs):
"""
password和email必需含有“l(fā)zl”這三個字母
:return:
"""
if "lzl" not in attrs['password'] or "lzl" not in attrs['email']:
raise serializers.ValidationError(detail='password和email必需含有“l(fā)zl”這三個字母')
else:
return attrs
2.5、views.py
的修改
-
ModelSerializer
類因為實現(xiàn)了簡單的.create()
方法和.update()
方法哆姻。所以之前的views.py
中的代碼只需要把之前的Serializer
類改成調(diào)用繼承了ModelSerializer
的類即可
2.6宣增、指定外鍵序列化輸出的值(從表指定主表外鍵)
主表:projcet
從表:interface
在interface副表中,外鍵是projcet
當使用ModelSerializer
進行序列化時矛缨,默認會對project外鍵進行處理爹脾,默認生成的是PrimaryKeyRelatedField序列化器字段,序列化輸出的是該interface對應的project表的id箕昭。
如果需要修改灵妨,那么需要顯示處理:
from rest_framework import serializers
from interfaces.models import Interfaces
from projects.serializer import ProjectModelSerializer
class InterfaceModelSerializer(serializers.ModelSerializer):
# 指定外鍵序列化輸出內(nèi)容(project是interface的外鍵字段)
# 1、StringRelatedField:此字段會被序列化為關聯(lián)對象字符串表達形式落竹,也就是__str__方法的內(nèi)容
project = serializers.StringRelatedField(label='所屬項目')
# 2泌霍、SlugRelatedField:指定序列化返回的字段,比如下面序列化的結果是關聯(lián)project表的leader字段的值
project = serializers.SlugRelatedField(label='所屬項目', slug_field='leader')
# 3述召、 指定返回關聯(lián)的project序列化器(需要指定read_only朱转,不然前端就需要輸入一個project序列化器)
project = ProjectModelSerializer((label='所屬項目', read_only=True)
class Meta:
model = Interfaces
fields = '__all__'
2.6、指定外鍵序列化輸出的值(主表指定從表)
主表中不會默認生成從表的關聯(lián)字段桨武,需要手動指定肋拔,并且字段名是從表名_set
。其它方法和和在從表指定主表的一樣呀酸。
class ProjectModelSerializer(serializers.ModelSerializer):
#注意字段名,并且由于是從表琼梆,多的一方性誉,要指定many=True
interfaces_set = serializers.StringRelatedField(label='項目接口', many=True)
class Meta:
model = Interfaces
fields = '__all__'