二、DRF框架中序列化和反序列化
阿新 • • 發佈:2020-10-22
資料校驗
比如
將前端傳遞的json格式資料轉化為python中的資料型別(模型類物件)叫做反序列化
將模型類物件轉化為json格式的資料叫做序列化
資料增刪改查流程
增
校驗請求引數-->反序列化-->儲存資料-->將儲存的物件序列化並返回
刪
判斷要刪除的資料是否存在-->執行資料庫刪除並返回
改
判斷要修改的資料是否存在-->校驗請求引數-->反序列化-->儲存資料-->將儲存的物件序列化並返回
查
查詢資料庫-->將資料序列化並返回
定義序列化器注意事項
1.定義的序列化器,必須繼承rest_framework中的serializers或者Serializer子類
2.定義的每一個類屬性要與模型類中對應
3.預設情況下,定義了哪些類屬性(序列化器欄位),那麼就會序列化輸出哪些欄位和哪些欄位需要進行反序列化輸入,如果不需要序列化輸出,不定義即可,如果不要返回ID,可以不用定義ID
欄位校驗順序:
4.欄位定義時的限制(包含validators列表條目從左到右進行校驗),通過之後才會開始對單欄位進行校驗,接下來是多欄位的校驗
View中進行序列化操作
a.序列化過程:將模型類物件(或查詢集物件)轉化為json資料
b.將模型類物件(或查詢集物件)傳給instance,可以進行序列化操作
c.通過序列化器ProjectSerializer物件的data屬性,可以獲取轉化後的值
project_qs:查詢到的模型類物件
ProjectSerializer:序列化器類
many=True:如果返回多條資料(列表),需要新增這個
instance:如果需要序列化輸出,需要給instance傳參
如:serializer = serializers.ProjectSerializer(instance=project_qs, many=True)
data:如果需要反序列化輸入(資料校驗),需要給data傳參
is_valid():呼叫該方法才能進行資料校驗
raise_exception=True:如果校驗通過,正常返回,如果不通過,會返回相應的錯誤資訊
serializer.validated_data:獲取校驗通過之後的資料
如:
serializer = serializers.ProjectSerializer(data=project_qs, many=True)
serializer.is_valid(raise_exception=True)
project=Projects.objects.creat(**serializer.validated_data)
序列化器欄位釋義
label,help_text選項相當於模型類中verbose_name,help_text
write_only=True,那麼當前欄位只能進行反序列化操作(資料校驗),也不會返回給前端
read_only=True,那麼當前欄位只能進行序列化操作輸出,不進行資料校驗(也就是前端可以不用傳這個值,後端仍會返回)
vaildators 該欄位使用的驗證器,是一個列表,裡面可以定義內建的一些校驗規則或自己寫校驗規則,按照列表的元素順序進行校驗,不管校驗有沒有通過,都會遍歷呼叫每一個校驗器
message:表示未通過校驗返回的錯誤資訊
UniqueValidator:驗證該欄位是否有重複
如:validators=[UniqueValidator(queryset=Projects.objects.all(),message="專案名稱不能重複")]
error_messages 自定義錯誤資訊的字典,key為序列化器欄位
如:error_messages={"max_length":"負責人長度不能超過50位元組","min_length":"負責人長度不能小於10位元組"}
其他序列化器欄位:
max_length 最大長度
min_length 最小長度
required 是否必填,預設是
trim_whitespace 是否截斷空白字元
max_value 最大值(針對int型別)
min_value 最小值(針對int型別)
required 表明該欄位在反序列化時必須輸入,預設True
default 反序列化時使用的預設值
allow_null 表明該欄位是否允許傳入None,預設False
label 用於HTML展示API頁面時,顯示的欄位名稱
help_text 用於HTML展示API頁面時,顯示的欄位幫助提示資訊
CharField 字串型別
IntegerField int型別
序列化器類內部定義校驗器
單欄位校驗
a.方法名稱必須以validate_作為字首,後面加上待校驗的欄位名
b.在內部定義必須把value 返回return出來
def validate_name(self,value): """ 校驗專案名是否以“專案”結尾 :return: """ if not value.endswith('專案'): raise serializers.ValidationError("專案名稱必須以專案結尾") return value多欄位聯合校驗 需要等單欄位校驗通過後,才會校驗多欄位,validate會把前端傳過來的引數作字典賦值給attrs
defvalidate(self, attrs):欄位校驗順序 validators列表條目從左到右進行校驗 ---->validate_name通過之後才會對單欄位進行校驗--->validate 再對多欄位進行校驗 序列化器類create方法
name = attrs["name"] leader = attrs["leader"] if "solememory" not in name and "solememory" not in leader: raise serializers.ValidationError("solememory必須在專案負責人或者專案名稱中包含") return attrs
def create(self, validated_data): """ 更新專案 :param validated_data: 校驗通過之後的專案資料 :return: 專案建立成功之後的模型類物件 """ project = Projects.objects.create(**validated_data) return project
project_qs:查詢到的模型類物件 當在view檢視中呼叫了serializer .save()方法時,save方法可以傳遞關鍵字引數(字典型別),會被create方法中的validated_data接收 在建立序列化器物件時,(這一步的時候:serializer = serializers.ProjectSerializer(data=project_qs) 如果只給data傳參,那麼使用序列化器物件呼叫save()方法時,只會呼叫creat()方法 序列化器類update方法
# instance引數接收的是更新前的引數,validated_data接收的是更新後的引數 def update(self, instance, validated_data): """ :param instance: 待更新的專案模型類物件--->接收的是one_project :param validated_data: 校驗通過之後的模型類物件--->接收的是python_data :return: 專案更新成功之後的模型類物件 """ instance.name = validated_data['name'] instance.leader = validated_data['leader'] instance.tester = validated_data['tester'] instance.programmer = validated_data['programmer'] instance.publish_app = validated_data['publish_app'] instance.desc = validated_data['desc'] instance.save() return instanceone_project:資料庫查詢到的模型類物件 python_data:前端傳遞過來的引數 在建立序列化器物件時,(這一步的時候:serializer = serializers.ProjectSerializer(instance=one_project, data=python_data) 如果給instance和data同時傳遞引數,當在view檢視中呼叫了serializer .save()方法時,會自動呼叫update方法 模型序列化器 因為在序列化器類中又要重新定義模型類中的欄位,而且兩邊的定義相差不大,所以可以定義Meta內部類,設定當前序列化器類的元資料資訊
class ProjectModelSerializer(serializers.ModelSerializer): #因為模型序列化器是自動根據模型類生成的,那麼我們如果有自定義校驗器,可以這樣寫, 這裡自定義的會覆蓋掉模型序列化器自動生成的欄位,但這裡不要輕易指定, 一般模型類沒有的欄位,可以在這裡寫,否則最好寫在下面的extra_kwargs 中 name = serializers.CharField(label="專案名稱", help_text="專案名稱", max_length=20, validators=[is_unique_project, cotain_keyword_project]) #如果要定義模型類中沒有的欄位,可以這樣寫,但記得新增在下面的fields中 email = serializers.EmailField(label='郵箱', allow_blank=True, allow_null=True, default='[email protected]', read_only=True) # 父表如果需要返回子表中的欄位,預設情況下,父表模型序列化器類不會建立子表字段,需要顯示建立 # 子表字段名為:子表類名小寫_set # 如果子表定義外來鍵欄位時,指定了related_name='intfaces',那麼這裡需要使用related_name使用的值 interfaces_set = serializers.StringRelatedField(many=True) class Meta: # 指定參照哪一個模型類 model = Projects # 指定模型類中的哪些欄位來生成序列化器欄位,__all__代表所有欄位 # 會自動將模型列中的主鍵新增read_only=True,因為id一般不需要前端傳 # fields = '__all__' # 可以在fields中使用元組指定哪些模型類欄位需要生成序列化器欄位,既需要輸入也需要輸出 # fields元組中指定的是所有序列化器欄位(模型類中不包含的欄位也需要在fields中指定) fields=('id', 'name', 'leader', 'tester', 'email ') # 排除模型類欄位,這裡面的欄位不用生成序列化器欄位 # exclude = ('create_time', 'update_time', 'desc') # 在read_only_fiels中指定的欄位會自動新增read_only=True,可惜沒有write_only的方法 # read_only_fiels= ('desc') # 是一個巢狀字典的字典 # 如果只需要改欄位中的一部分內容,就沒必要重新再像上面一樣寫一個name,可以在這裡指定,以修改的欄位名作為key extra_kwargs = { 'name': { 'error_messages': {'max_length': '專案名稱的長度不能大於20位元組'}, 'read_only': True, 'min_length': 50, 'validators': [is_unique_project, cotain_keyword_project] }, 'leader': { 'label': '負責人', 'write_only': True } } #ModelSerializer內部有creat和update方法,無需自己定義 # 假如email欄位設定的是write_only,那麼該欄位通過校驗之後會呼叫create方法,但是資料庫中不存在這個欄位,會導致報錯,這個時候可以重寫create方法 def create(self, validated_data): # 刪除emalil後再次呼叫create方法 email = validated_data.pop('email') super().create(validated_data)外來鍵表中的模型序列化器
class ProjectModelSerializer(serializers.ModelSerializer): class Meta: model = Projects fields = '__all__' class InterfacesModelSerializer(serializers.ModelSerializer): # 會預設將外來鍵欄位project生成PrimaryKeyRelatedField型別,預設返回的是父表對應的id值 # 可以重寫預設生成的project,重寫改成了StringRelatedField方法,會自動呼叫父表的__str__方法,輸出父表的name # project = serializers.StringRelatedField(label="所屬專案") # 使用父表的模型序列化器來建立,就可以獲取父表中的一些欄位 project = ProjectModelSerializer(read_only=True) class Meta: # 指定參照哪一個模型 model = Interfaces fields = '__all__'