6. 序列化
兩大功能:
1. 對請求數據的驗證
2. 對querset進行序列化
一.序列化:
利用
ser.data
獲得經過序列化得到的數據,ser爲經過數據庫查詢得到的query對象(ret = models.Role.objects.all())
1.寫類
兩種基本寫法:
from rest_framework.serializers import ...
一種繼承自
Serializer
,
第二種繼承自ModelSerializer
,自動數據庫表裏邊,自動生成Serializer的字段
class RolesSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField()
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
# fields = "__all__" # 可以自動生成所有字段,但是默認拿的都是最基本的
fields = ['id','username','password',] # 寫數據庫的字段
2.字段
a.
title = serializers.CharField(source="xxx.xxx.xx.xx")
重點:獲取choice字段顯示
-
source
爲對應數據庫的字段名稱,這樣前邊的title就可以隨便定義了 -
source
針對如含choice
等字段,可以執行get_字段名_display
方法 進行顯示,如source='get_usertype_display'
-
source
針對外鍵等情況,可以使用xx.屬性名
,進行調用,如:source='group.id'
-
當要查的不只是一個數據,可以用
SerializerMethodField
進行自定義顯示,可以定義一個
以get_
開頭的方法/函數,函數返回什麼,就顯示什麼(如下:get_rls
)
b.
title = serializers.SerializerMethodField()
class UserInfoSerializer(serializers.ModelSerializer):
rls = serializers.SerializerMethodField() # 自定義顯示
haha = serializers.CharField(source='get_usertype_display')
class Meta:
model = models.UserInfo
# fields = "__all__" # 可以自動生成多有字段,但是默認拿的都是最基本的
# 可以跟自定義的字段,混合着中。對於額外數據也可以depth進行深度提取,拿到更多數據
# 對於有格外操作的,可以定義上邊單獨字段,然後添加到files中
fields = ['id','username','password','rls','haha']
# 自定義方法
def get_rls(self, row):
role_obj_list = row.roles.all()
ret = []
for item in role_obj_list:
ret.append({'id':item.id,'title':item.title})
return ret
c. 自定義類
- 可以繼承CharFiled等字段,進行自己的再封裝。用的不多
3. 自動序列化連表、深度depth
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id','username','password','group','roles'] #可對應添加含字段的字段名稱
depth = 1 # 官方建議0 ~ 10(取數據的深度,如果只拿到數據ID,可以再往深的取對應的描述文字)
# 層數越深,數據越多,檢索越多,影響性能,平時到3已經很大了
4. 生成鏈接(反向解析)
url(r'^(?P<version>[v1|v2])/group/(?P<xxx>\d+)$',views.GroupView.as_view(),name='gp')
class UserInfoSerializer(serializers.ModelSerializer):
group = serializers.HyperlinkedIdentityField(view_name='gp',lookup_field='group_id',lookup_url_kwarg='xxx')
# view_name >> url處的別名
# lookup_field >> url中的xxx匹配的內容,針對數據庫中所要查詢字段的索引值
# lookup_url_kwarg >> 取url中正則匹配的名字
class Meta:
model = models.UserInfo
# fields = "__all__"
fields = ['id','username','password','group','roles']
depth = 0
class UserInfoView(APIView):
def get(self,request,*args,**kwargs):
users = models.UserInfo.objects.all()
ser = UserInfoSerializer(instance=users,many=True,context={'request': request})
ret = json.dumps(ser.data, ensure_ascii=False)
return HttpResponse(ret)
源碼:
對象,
Serializer
類處理;
QuerySet,ListSerializer
類處理;
# serializer.data
2.請求數據校驗:
對request請求過來的數據進行驗證,比如不允許傳空值,然後根據校驗規則進行相應。如:發{"pwd":""}
,經過驗證返回{"pwd":["標題不能爲空"]}
class XXValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if not value.startswith(self.base):
message = '標題必須以 %s 爲開頭。' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 執行驗證之前調用,serializer_fields是當前字段對象
pass
class UserGroupSerializer(serializers.Serializer):
# 基於title這個字段名進行,驗證;
# 就是說請求數據,必須需包含'title',並且不能爲空
title = serializers.CharField(error_messages={'required':'標題不能爲空'},validators=[XXValidator('老男人'),])
# error_messages={'required':'標題不能爲空'} #自定義出錯的信息
# validators=[XXValidator('老男人'),] #自定義驗證規則(上邊的XXValidator)
class UserGroupView(APIView):
def post(self,request,*args,**kwargs):
ser = UserGroupSerializer(data=request.data) #做校驗時,傳入請求數據
if ser.is_valid():
print(ser.validated_data['title'])
else:
print(ser.errors)
return HttpResponse('提交數據')
問: 自定義驗證規則時,需要鉤子函數?請問鉤子函數如何寫?
答:從is_vaild()
方法開始找源碼,注意self要先從自己定義的類進行查找,然後在一步步深入。