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要先从自己定义的类进行查找,然后在一步步深入。