<table style="height: 30px; background-color: #afeeee; width: 1266px; ; width: 1266px;" border="0">
<tr><td><span style="font-size: 16px;">一、简介</td>
</tr></table>
django rest framework 中的序列化组件,可以说是其核心组件,也是我们平时使用最多的组件,它不仅仅有序列化功能,更提供了数据验证的功能(与django中的form类似)。
便于展现的序列化操作,我们需要在model添加外键、多对多情况。以下是新的models(请删除原有的数据库,重新migrate):
models.py
user_type_choice =<span style="color: #000000;"> (
(1,<span style="color: #800000;">"<span style="color: #800000;">普通用户<span style="color: #800000;">"<span style="color: #000000;">),(2,<span style="color: #800000;">"<span style="color: #800000;">会员<span style="color: #800000;">"<span style="color: #000000;">),)
user_type = models.IntegerField(choices=<span style="color: #000000;">user_type_choice)
username = models.CharField(max_length=32,unique=<span style="color: #000000;">True)
password = models.CharField(max_length=64<span style="color: #000000;">)
group = models.ForeignKey(to=<span style="color: #800000;">'<span style="color: #800000;">UserGroup<span style="color: #800000;">',null=True,blank=<span style="color: #000000;">True)
roles = models.ManyToManyField(to=<span style="color: #800000;">'<span style="color: #800000;">Role<span style="color: #800000;">'<span style="color: #000000;">)
<span style="color: #0000ff;">class<span style="color: #000000;"> UserToken(models.Model):
user = models.OneToOneField(to=<span style="color: #000000;">UserInfo)
token = models.CharField(max_length=64<span style="color: #000000;">)
<span style="color: #0000ff;">class<span style="color: #000000;"> UserGroup(models.Model):
<span style="color: #800000;">"""<span style="color: #800000;">用户组<span style="color: #800000;">"""<span style="color: #000000;">
name = models.CharField(max_length=32,unique=<span style="color: #000000;">True)
<span style="color: #0000ff;">class<span style="color: #000000;"> Role(models.Model):
<span style="color: #800000;">"""<span style="color: #800000;">角色<span style="color: #800000;">"""<span style="color: #000000;">
name = models.CharField(max_length=32,unique=True)
在urls.py中添加新的角色url,以前的url为了减少干扰,在这里进行注释:
</span><span style="color: #008000;">#</span><span style="color: #008000;"> url(r'^api/v1/auth',views.AuthView.as_view()),</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> url(r'^api/v1/order',views.OrderView.as_view()),</span>
url(r<span style="color: #800000;">'</span><span style="color: #800000;">^api/v1/roles</span><span style="color: #800000;">'</span><span style="color: #000000;">,views.RoleView.as_view()),<span style="color: #ff6600;"># 角色视图
</span></span><span style="color: #008000;">#</span><span style="color: #008000;"> url(r'^api/(?P<version>[v1|v2]+)/user',views.UserView.as_view(),name="user_view"),</span>
]
views.py
id=serializers.IntegerField() <span style="color: #008000;">#<span style="color: #008000;">定义需要提取的序列化字段,名称和model中定义的字段相同
name=<span style="color: #000000;">serializers.CharField()
<span style="color: #0000ff;">class<span style="color: #000000;"> RoleView(APIView):
<span style="color: #800000;">"""<span style="color: #800000;">角色<span style="color: #800000;">"""
<span style="color: #0000ff;">def get(self,request,*args,**<span style="color: #000000;">kwargs):
roles=<span style="color: #000000;">models.Role.objects.all()
res=RolesSerializer(instance=roles,many=True) <span style="color: #008000;">#<span style="color: #008000;">instance接受queryset对象或者单个model对象,当有多条数据时候,使用many=True,单个对象many=False
<span style="color: #0000ff;">return HttpResponse(json.dumps(res.data,ensure_ascii=False))
使用浏览器访问http://127.0.0.1:8000/api/v1/roles,结果如下:
2.自定义序列化字段
当数据模型中有外键或者多对多时候,这时候就需要自定义序列化了
新增用户信息url
</span><span style="color: #008000;">#</span><span style="color: #008000;"> url(r'^api/v1/auth',url(r</span><span style="color: #800000;">'</span><span style="color: #800000;">^api/v1/userinfo</span><span style="color: #800000;">'</span><span style="color: #000000;">,views.UserinfoView.as_view()),<span style="color: #ff6600;">#<a href="/tag/yonghu/" target="_blank" class="keywords">用户</a>信息
</span></span><span style="color: #008000;">#</span><span style="color: #008000;"> url(r'^api/(?P<version>[v1|v2]+)/user',</span>
]
UserinfoView和序列化类
id=serializers.IntegerField() <span style="color: #008000;">#<span style="color: #008000;">定义需要提取的序列化字段,名称和model中定义的字段相同
<span style="color: #000000;">
username=<span style="color: #000000;">serializers.CharField()
password=<span style="color: #000000;">serializers.CharField()
<span style="color: #008000;">#<span style="color: #008000;">sss=serializers.CharField(source='user_type') #该方法只能拿到user_type的ID
sss=serializers.CharField(source=<span style="color: #800000;">'<span style="color: #800000;">get_user_type_display<span style="color: #800000;">') <span style="color: #008000;">#<span style="color: #008000;">自定义字段名称,和数据模型不一致,需要指定source本质调用get_user_type_display()方法获取数据
gp=serializers.CharField(source=<span style="color: #800000;">'<span style="color: #800000;">group.name<span style="color: #800000;">') <span style="color: #008000;">#<span style="color: #008000;">本质拿到group对象,取对象的name,
<span style="color: #008000;">#<span style="color: #008000;">rl=serializers.CharField(source='roles.all.first.name')
rl=serializers.SerializerMethodField() <span style="color: #008000;">#<span style="color: #008000;">多对多序列化方法一
<span style="color: #0000ff;">def get_rl(self,obj): <span style="color: #008000;">#<span style="color: #008000;">名称固定:get_定义的字段名称
<span style="color: #800000;">"""<span style="color: #800000;">
自定义序列化
:param obj:传递的model对象,这里已经封装好的
:return:
<span style="color: #800000;">"""<span style="color: #000000;">
roles=obj.roles.all().values() <span style="color: #008000;">#<span style="color: #008000;">获取所有的角色
<span style="color: #0000ff;">return</span> list(roles) <span style="color: #008000;">#</span><span style="color: #008000;">返回的结果一定有道是json可序列化的对象</span>
<span style="color: #0000ff;">class<span style="color: #000000;"> UserinfoView(APIView):
<span style="color: #800000;">"""用户信息<span style="color: #800000;">"""
<span style="color: #0000ff;">def get(self,**<span style="color: #000000;">kwargs):
users=<span style="color: #000000;">models.UserInfo.objects.all()
res=UserinfoSerializer(instance=users,ensure_ascii=False))
访问http://127.0.0.1:8000/api/v1/userinfo,查看结果:
除了以上的Serializer,还可以使用ModelSerializer,ModelSerializer继承了serializer,其结果和上面示例一样:
<span style="color: #0000ff;">return</span> list(roles) <span style="color: #008000;">#</span><span style="color: #008000;">返回的结果一定有道是json可序列化的对象</span>
<span style="color: #0000ff;">class</span><span style="color: #000000;"> <a href="/tag/Meta/" target="_blank" class="keywords">Meta</a>:
model </span>=<span style="color: #000000;"> models.UserInfo
fields </span>= [<span style="color: #800000;">'</span><span style="color: #800000;">id</span><span style="color: #800000;">'</span>,<span style="color: #800000;">'</span><span style="color: #800000;">username</span><span style="color: #800000;">'</span>,<span style="color: #800000;">'</span><span style="color: #800000;">password</span><span style="color: #800000;">'</span>,<span style="color: #800000;">'</span><span style="color: #800000;">sss</span><span style="color: #800000;">'</span>,<span style="color: #800000;">'</span><span style="color: #800000;">rl</span><span style="color: #800000;">'</span>,<span style="color: #800000;">'</span><span style="color: #800000;">gp</span><span style="color: #800000;">'</span>] <span style="color: #008000;">#</span><span style="color: #008000;">配置要序列化的字段</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> fields = "__all__" 使用model中所有的字段</span>
<span style="color: #0000ff;">class
<span style="color: #000000;"> UserinfoView(APIView):<span style="color: #800000;">"""<span style="color: #800000;">用户信息<span style="color: #800000;">"""
<span style="color: #0000ff;">def get(self,ensure_ascii=False))
3.连表序列化以及深度控制
使用depth进行深度控制,越深其序列化的细读越高
</span><span style="color: #0000ff;">class</span><span style="color: #000000;"> <a href="/tag/Meta/" target="_blank" class="keywords">Meta</a>:
model </span>=<span style="color: #000000;"> models.UserInfo
</span><span style="color: #008000;">#</span><span style="color: #008000;">fields = "__all__" # 使用model中所有的字段</span>
fields = [<span style="color: #800000;">'</span><span style="color: #800000;">id</span><span style="color: #800000;">'</span>,<span style="color: #800000;">'</span><span style="color: #800000;">group</span><span style="color: #800000;">'</span>,<span style="color: #800000;">'</span><span style="color: #800000;">roles</span><span style="color: #800000;">'</span>] <span style="color: #008000;">#</span><span style="color: #008000;"> 配置要序列化的字段</span>
depth = 1 <span style="color: #008000;">#</span><span style="color: #008000;">系列化深度,1~10,建议使用不超过3</span>
<span style="color: #0000ff;">class
<span style="color: #000000;"> UserinfoView(APIView):<span style="color: #800000;">"""<span style="color: #800000;">用户信息<span style="color: #800000;">"""
<span style="color: #0000ff;">def get(self,ensure_ascii=False))
请求http://127.0.0.1:8000/api/v1/userinfo,结果如下:
4.序列化字段url
urls.py新加入组url
</span><span style="color: #008000;">#</span><span style="color: #008000;"> url(r'^api/v1/auth',url(r</span><span style="color: #800000;">'</span><span style="color: #800000;">^api/v1/group/(?P<xxx>\d+)</span><span style="color: #800000;">'</span>,views.GroupView.as_view(),name=<span style="color: #800000;">'</span><span style="color: #800000;">gp</span><span style="color: #800000;">'</span><span style="color: #000000;">),<span style="color: #ff6600;"># 新加入组url
</span></span><span style="color: #008000;">#</span><span style="color: #008000;"> url(r'^api/(?P<version>[v1|v2]+)/user',</span>
]
views.py
<span style="color: #0000ff;">class<span style="color: #000000;"> Meta:
model =<span style="color: #000000;"> models.UserGroup
fields = <span style="color: #800000;">"<span style="color: #800000;">all<span style="color: #800000;">"<span style="color: #000000;">
depth =<span style="color: #000000;"> 0 <span style="color: #0000ff;">class<span style="color: #000000;"> GroupView(APIView):
<span style="color: #0000ff;">def get(self,**<span style="color: #000000;">kwargs):
group_id</span>=kwargs.get(<span style="color: #800000;">'</span><span style="color: #800000;">xxx</span><span style="color: #800000;">'</span><span style="color: #000000;">)
group_obj</span>=models.UserGroup.objects.get(id=<span style="color: #000000;">group_id)
res</span>=UserGroupSerializer(instance=group_obj,many=False) <span style="color: #008000;">#</span><span style="color: #008000;">instance接受queryset对象或者单个model对象,当有多条数据时候,使用many=True,ensure_ascii=False))</pre>
此时访问组信息:http://127.0.0.1:8000/api/v1/group/1,结果如下:
在查看用户信息,此时生成的组就是超链接形式了(便于查看json数据,这里用postman发请求):
<table style="height: 30px; background-color: #afeeee; width: 1266px; ; width: 1266px;" border="0">
<tr><td><span style="font-size: 16px;">三、源码剖析</td>
</tr></table>
1.类的基本知识
2.以ModelSerializer为例,无__new__方法,其父类Serializer也没有,在往上父类BaseSerializer中含有__new__方法,分析请看注释,下面是源码部分:
Note that we strongly restrict the ordering of operations/properties
that may be used on the serializer in order to enforce correct usage.
In particular,if a `data=` argument is passed then:
.is_valid() - Available.
.initial_data - Available.
.validated_data - Only available after calling `is_valid()`
.errors - Only available after calling `is_valid()`
.data - Only available after calling `is_valid()`
If a `data=` argument is not passed then:
.is_valid() - Not available.
.initial_data - Not available.
.validated_data - Not available.
.errors - Not available.
.data - Available.
</span><span style="color: #800000;">"""</span>
<span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span>(self,instance=None,data=empty,**<span style="color: #000000;">kwargs): <span style="color: #ff6600;"># many=False<a href="/tag/houzhixing/" target="_blank" class="keywords">后执行</a>的构造<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a></span>
self.instance </span>=<span style="color: #000000;"> instance
</span><span style="color: #0000ff;">if</span> data <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> empty:
self.initial_data </span>=<span style="color: #000000;"> data
self.partial </span>= kwargs.pop(<span style="color: #800000;">'</span><span style="color: #800000;">partial</span><span style="color: #800000;">'</span><span style="color: #000000;">,False)
self._context </span>= kwargs.pop(<span style="color: #800000;">'</span><span style="color: #800000;">context</span><span style="color: #800000;">'</span><span style="color: #000000;">,{})
kwargs.pop(</span><span style="color: #800000;">'</span><span style="color: #800000;">many</span><span style="color: #800000;">'</span><span style="color: #000000;">,None)
super(BaseSerializer,self).</span><span style="color: #800080;">__init__</span>(**<span style="color: #000000;">kwargs)
</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__new__</span>(cls,**<span style="color: #000000;">kwargs):
</span><span style="color: #008000;">#</span><span style="color: #008000;"> We override this method in order to automagically create</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> `ListSerializer` classes instead when `many=True` is set.</span>
<span style="color: #0000ff;">if</span> kwargs.pop(<span style="color: #800000;">'</span><span style="color: #800000;">many</span><span style="color: #800000;">'</span><span style="color: #000000;">,False): <span style="color: #ff6600;"># many参数,如果有则执行cls.many_init,没有则执行super(BaseSerializer).__new__
</span></span><span style="color: #0000ff;">return</span> cls.many_init(*args,**<span style="color: #000000;">kwargs) <span style="color: #ff6600;"># many=True,表示对QuerySet进行处理,走该逻辑,
</span></span><span style="color: #0000ff;">return</span> super(BaseSerializer,cls).<span style="color: #800080;">__new__</span>(cls,**kwargs)<span style="color: #ff6600;"> # many = False ,表示对单独的对象进行处理</span></pre>
执行玩__new__方法接着执行__init__构造方法,此时有根据many值不同执行不同的构造方法,当many=True时候执行cls.many_init方法,
Note that we're over-caut<a href="/tag/IoU/" target="_blank" class="keywords">IoU</a>s in passing most arguments to both parent
and child classes in order to try to cover the general case. If you're
overriding this method you'll probably want something much simpler,eg:
@classmethod
def many_init(cls,**kwargs):
kwargs['child'] = cls()
return CustomListSerializer(*args,**kwargs)
</span><span style="color: #800000;">"""</span><span style="color: #000000;">
allow_empty </span>= kwargs.pop(<span style="color: #800000;">'</span><span style="color: #800000;">allow_empty</span><span style="color: #800000;">'</span><span style="color: #000000;">,None)
child_serializer </span>= cls(*args,**<span style="color: #000000;">kwargs)
list_kwargs </span>=<span style="color: #000000;"> {
</span><span style="color: #800000;">'</span><span style="color: #800000;">child</span><span style="color: #800000;">'</span><span style="color: #000000;">: child_serializer,}
</span><span style="color: #0000ff;">if</span> allow_empty <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> None:
list_kwargs[</span><span style="color: #800000;">'</span><span style="color: #800000;">allow_empty</span><span style="color: #800000;">'</span>] =<span style="color: #000000;"> allow_empty
list_kwargs.update({
key: value </span><span style="color: #0000ff;">for</span> key,value <span style="color: #0000ff;">in</span><span style="color: #000000;"> kwargs.items()
</span><span style="color: #0000ff;">if</span> key <span style="color: #0000ff;">in</span><span style="color: #000000;"> LIST_SERIALIZER_KWARGS
})
<a href="/tag/Meta/" target="_blank" class="keywords">Meta</a> </span>= getattr(cls,<span style="color: #800000;">'</span><span style="color: #800000;"><a href="/tag/Meta/" target="_blank" class="keywords">Meta</a></span><span style="color: #800000;">'</span><span style="color: #000000;">,None)
list_serializer_class </span>= getattr(<a href="/tag/Meta/" target="_blank" class="keywords">Meta</a>,<span style="color: #800000;">'</span><span style="color: #800000;">list_serializer_class</span><span style="color: #800000;">'</span><span style="color: #000000;">,ListSerializer)
</span><span style="color: #0000ff;">return</span> list_serializer_class(*args,**list_kwargs) <span style="color: #ff6600;"># 最后使用ListSerializer进行实例化</span></pre>
从上面源码中我们知道,对于单独的对象,采用的是Serializer类进行处理,若对象是QuerySet类型(多个对象列表),采用LIstSeriallizer处理,此时我们调用对象的data属性获取结果(示例中这使用的是res.data),下面是源码(寻找时候先从子类找,无该属性就去父类找):
</span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span> hasattr(self,<span style="color: #800000;">'</span><span style="color: #800000;">_data</span><span style="color: #800000;">'</span><span style="color: #000000;">):
</span><span style="color: #0000ff;">if</span> self.instance <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">not</span> None <span style="color: #0000ff;">and</span> <span style="color: #0000ff;">not</span> getattr(self,<span style="color: #800000;">'</span><span style="color: #800000;">_errors</span><span style="color: #800000;">'</span><span style="color: #000000;">,None)<span style="color: #ff6600;">:# 判断有无<a href="/tag/cuowu/" target="_blank" class="keywords">错误</a>,无<a href="/tag/cuowu/" target="_blank" class="keywords">错误</a>进行序列化</span>
self._data </span>=<span style="color: #000000;"> self.to_representation(self.instance) <span style="color: #ff6600;"># 将instance(QuerySet对象)传入,开始序列化
</span></span><span style="color: #0000ff;">elif</span> hasattr(self,<span style="color: #800000;">'</span><span style="color: #800000;">_validated_data</span><span style="color: #800000;">'</span>) <span style="color: #0000ff;">and</span> <span style="color: #0000ff;">not</span> getattr(self,None):
self._data </span>=<span style="color: #000000;"> self.to_representation(self.validated_data) </span></pre>
= self._data
从以上源码中可以看出,序列化方法是通过调用类的self.to_representation方法进行序列化,下面我们看Serializer类的to_representation方法
</span><span style="color: #0000ff;">for</span> field <span style="color: #0000ff;">in</span><span style="color: #000000;"> fields: <span style="color: #ff6600;"># 循环定义的字段,这个字段可以是我们自己定义的,也可以是model中的字段
</span></span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
attribute </span>=<span style="color: #000000;"> field.get_attribute(instance) <span style="color: #ff6600;">#<a href="/tag/diaoyong/" target="_blank" class="keywords">调用</a>字段的get_attribute<a href="/tag/fangfa/" target="_blank" class="keywords">方法</a>(参数是对象),在示例中可以理解为group.get_attribute(group_obj),
</span></span><span style="color: #0000ff;">except</span><span style="color: #000000;"> SkipField:
</span><span style="color: #0000ff;">continue</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> We skip `to_representation` for `None` values so that fields do</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> not have to explicitly deal with that case.</span>
<span style="color: #008000;">#
<span style="color: #008000;">#<span style="color: #008000;"> For related fields with use_pk_only_optimization
we need to<span style="color: #008000;">#<span style="color: #008000;"> resolve the pk value.
check_for_none = attribute.pk <span style="color: #0000ff;">if isinstance(attribute,PKOnlyObject) <span style="color: #0000ff;">else<span style="color: #000000;"> attribute
<span style="color: #0000ff;">if check_for_none <span style="color: #0000ff;">is<span style="color: #000000;"> None:
ret[field.field_name] =<span style="color: #000000;"> None
<span style="color: #0000ff;">else<span style="color: #000000;">:
ret[field.field_name] =<span style="color: #000000;"> field.to_representation(attribute)
</span><span style="color: #0000ff;">return</span> ret</pre>
以上源码中,调用field.get_attribute(instance)方法获取每个字段的数据,下面是field.get_attribute(instance)源码(在Field中)
调用get_attribute函数,进一步出来,需要分析self.source_attrs参数,下面是self.source_attrs部分源码:
以上分析self.source_attrs是一个列表(由source参数按点分割而来),继续回到get_attribute函数,下面是其源码:
Also accepts either attribute lookup on objects or dictionary lookups.
</span><span style="color: #800000;">"""</span> <span style="color: #ff6600;"># attrs:['group','name']或者['get_user_type_display',]</span>
<span style="color: #0000ff;">for</span> attr <span style="color: #0000ff;">in</span><span style="color: #000000;"> attrs: # 循环列表
</span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> isinstance(instance,collections.Mapping): <span style="color: #ff6600;">#若果是model字段映射(DRF的内部字段转化),直接<a href="/tag/diaoyong/" target="_blank" class="keywords">调用</a>model类的</span>
instance </span>=<span style="color: #000000;"> instance[attr]<span style="color: #ff6600;">#重新赋值,此时的instance已经改变
</span></span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
instance </span>=<span style="color: #000000;"> getattr(instance,attr) <span style="color: #ff6600;">#否则,使用反射<a href="/tag/huoqu/" target="_blank" class="keywords">获取</a>结果,如instance=getattr(userinfo_obj,group)
</span></span><span style="color: #0000ff;">except</span><span style="color: #000000;"> ObjectDoesNotExist:
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> None
</span><span style="color: #0000ff;">if</span><span style="color: #000000;"> is_simple_callable(instance): <span style="color: #ff6600;">#判断是否是可执行,此时如我们示例中的get_user_type_display,其判断过程在类似下面TIPS中,这里不再做过多说明
</span></span><span style="color: #0000ff;">try</span><span style="color: #000000;">:
instance </span>=<span style="color: #000000;"> instance() <span style="color: #ff6600;">#重新赋值,加括号进行执行
</span></span><span style="color: #0000ff;">except</span><span style="color: #000000;"> (AttributeError,KeyError) as exc:
</span><span style="color: #008000;">#</span><span style="color: #008000;"> If we raised an Attribute or KeyError here it'd get treated</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> as an omitted field in `Field.get_attribute()`. Instead we</span>
<span style="color: #008000;">#</span><span style="color: #008000;"> raise a ValueError to ensure the exception is not masked.</span>
<span style="color: #0000ff;">raise</span> ValueError(<span style="color: #800000;">'</span><span style="color: #800000;">Exception raised in callable attribute "{0}"; original exception was: {1}</span><span style="color: #800000;">'</span><span style="color: #000000;">.format(attr,exc))
</span><span style="color: #0000ff;">return</span> instance</pre>
TIPS:判断是否是可执行方法
<span style="color: #0000ff;">if<span style="color: #000000;"> isinstance(arg,types.FunctionType,):
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">yes<span style="color: #800000;">'<span style="color: #000000;">)
arg()
<span style="color: #0000ff;">else<span style="color: #000000;">:
<span style="color: #0000ff;">print(<span style="color: #800000;">'<span style="color: #800000;">NO<span style="color: #800000;">'<span style="color: #000000;">)
func(<span style="color: #0000ff;">lambda :1<span style="color: #000000;">)
func(111<span style="color: #000000;">)
<span style="color: #008000;">#<span style="color: #008000;">执行结果:
<span style="color: #000000;">yes
NO
从上面的源码分析来看,序列化本质是使用了django的orm的QuerSet或者单个model对象特性,利用反射或者方法进行序列化。
DRF的数据验证功能与django的form有点类似,示例:获取数据使用的是全局配置的json解析器,在中已经介绍:
</span><span style="color: #0000ff;">def</span> post(self,**<span style="color: #000000;">kwargs):
ret</span>=CheckGroupData(data=request.data)<span style="color: #008000;">#</span><span style="color: #008000;">这里配置了全局json解析器,使用request.data直接<a href="/tag/huoqu/" target="_blank" class="keywords">获取</a>数据</span>
<span style="color: #0000ff;">if</span><span style="color: #000000;"> ret.is_valid():
</span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ret.validated_data)
</span><span style="color: #008000;">#</span><span style="color: #008000;"><a href="/tag/huoqu/" target="_blank" class="keywords">获取</a>某个字段数据ret.validated_data.get('name')</span>
<span style="color: #0000ff;">return</span> HttpResponse(<span style="color: #800000;">'</span><span style="color: #800000;">数据验证成功</span><span style="color: #800000;">'</span><span style="color: #000000;">)
</span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
</span><span style="color: #0000ff;">print</span><span style="color: #000000;">(ret.errors)
</span><span style="color: #0000ff;">return</span> HttpResponse(<span style="color: #800000;">'</span><span style="color: #800000;">数据验证失败</span><span style="color: #800000;">'</span>)</pre>
使用postman向http://127.0.0.1:8000/api/v1/group/1,发送json数据,结果如下:
后台结果:
验证流程生效。
2.自定义验证
和django form功能一样,DRF序列化支持自定义数据验证,示例:
</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__call__</span><span style="color: #000000;">(self,value): <span style="color: #ff6600;">#value是字段值,默认传递
</span></span><span style="color: #0000ff;">if</span> value == <span style="color: #800000;">'</span><span style="color: #800000;">wd</span><span style="color: #800000;">'</span><span style="color: #000000;">:
message </span>= <span style="color: #800000;">"</span><span style="color: #800000;">关键字%s不能是%s</span><span style="color: #800000;">"</span>%<span style="color: #000000;">(self.base,value)
</span><span style="color: #0000ff;">raise</span><span style="color: #000000;"> serializers.ValidationError(message)
<span style="color: #0000ff;">class<span style="color: #000000;"> MySerializer(serializers.Serializer):name = serializers.CharField(validators=[MyValidation(base=<span style="color: #800000;">'<span style="color: #800000;">name_field<span style="color: #800000;">'<span style="color: #000000;">),]) <span style="color: #0000ff;">class<span style="color: #000000;"> GroupView(APIView):
<span style="color: #0000ff;">def get(self,**<span style="color: #000000;">kwargs):
ret=MySerializer(data=request.data)<span style="color: #008000;">#<span style="color: #008000;">这里配置了全局json解析器,使用request.data直接获取数据
<span style="color: #0000ff;">if<span style="color: #000000;"> ret.is_valid():
<span style="color: #0000ff;">print<span style="color: #000000;">(ret.validated_data)
<span style="color: #008000;">#<span style="color: #008000;">获取某个字段数据ret.validated_data.get('name')
<span style="color: #0000ff;">return HttpResponse(<span style="color: #800000;">'<span style="color: #800000;">数据验证成功<span style="color: #800000;">'<span style="color: #000000;">)
<span style="color: #0000ff;">else<span style="color: #000000;">:
<span style="color: #0000ff;">print<span style="color: #000000;">(ret.errors)
<span style="color: #0000ff;">return HttpResponse(<span style="color: #800000;">'<span style="color: #800000;">数据验证失败<span style="color: #800000;">')
发送{"name":"wd"}数据进行验证结果如下:
3.钩子函数
对于自定义验证来说,DRF和django的form组件一样也给我们内置了钩子函数,用于验证。
验证流程:
is_valid-->self.run_validation-->to_internal_value-->to_internal_value-->validate_字段名称(执行字段验证,钩子方法)-->validate_method(钩子验证方法)
</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> validate_name(self,value):<span style="color: #ff6600;"> # 验证的字段值
</span></span><span style="color: #0000ff;">if</span> value.startswith(<span style="color: #800000;">"</span><span style="color: #800000;">w</span><span style="color: #800000;">"</span><span style="color: #000000;">):
</span><span style="color: #0000ff;">raise</span> serializers.ValidationError(<span style="color: #800000;">'</span><span style="color: #800000;">name字段不能以w开头</span><span style="color: #800000;">'</span><span style="color: #000000;">)
</span><span style="color: #0000ff;">else</span><span style="color: #000000;">:
</span><span style="color: #0000ff;">return</span><span style="color: #000000;"> value <span style="color: #ff6600;">#注意通过验证,必须返回其值
<span style="color: #0000ff;">class<span style="color: #000000;"> GroupView(APIView):<span style="color: #0000ff;">def get(self,使用request.data直接获取数据
<span style="color: #0000ff;">if<span style="color: #000000;"> ret.is_valid():
<span style="color: #0000ff;">print<span style="color: #000000;">(ret.validated_data)
<span style="color: #008000;">#<span style="color: #008000;">获取某个字段数据ret.validated_data.get('name')
<span style="color: #0000ff;">return HttpResponse(<span style="color: #800000;">'<span style="color: #800000;">数据验证成功<span style="color: #800000;">'<span style="color: #000000;">)
<span style="color: #0000ff;">else<span style="color: #000000;">:
<span style="color: #0000ff;">print<span style="color: #000000;">(ret.errors)
<span style="color: #0000ff;">return HttpResponse(<span style="color: #800000;">'<span style="color: #800000;">数据验证失败<span style="color: #800000;">')
同样发送json数据{"name":"wd"}进行验证,结果如下: