Django Rest Framework源码剖析(六)-----序列化(serializers)

<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

django.db <span style="color: #0000ff;">class<span style="color: #000000;"> UserInfo(models.Model):
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)

二、使用1.基本使用

在urls.py中添加新的角色url,以前的url为了减少干扰,在这里进行注释:

django.conf.urls app01 urlpatterns =<span style="color: #000000;"> [

</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; url(r'^api/v1/auth',views.AuthView.as_view()),</span>
<span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; url(r'^api/v1/order',views.OrderView.as_view()),</span>
url(r<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;^api/v1/roles</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,views.RoleView.as_view()),<span style="color: #ff6600;"&gt;# 角色视图
</span></span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; url(r'^api/(?P<version>[v1|v2]+)/user',views.UserView.as_view(),name="user_view"),</span>

]

views.py

rest_framework rest_framework.views django.shortcuts app01 <span style="color: #0000ff;">class RolesSerializer(serializers.Serializer): <span style="color: #008000;">#<span style="color: #008000;">定义序列化类
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

django.conf.urls app01 urlpatterns =<span style="color: #000000;"> [

</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; url(r'^api/v1/auth',url(r</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;^api/v1/userinfo</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,views.UserinfoView.as_view()),<span style="color: #ff6600;"&gt;#用户信息
</span></span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; url(r'^api/(?P<version>[v1|v2]+)/user',</span>

]

UserinfoView和序列化类

rest_framework rest_framework.views django.shortcuts app01 <span style="color: #0000ff;">class UserinfoSerializer(serializers.Serializer): <span style="color: #008000;">#<span style="color: #008000;">定义序列化类
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;"&gt;return</span> list(roles)  <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;返回的结果一定有道是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,其结果和上面示例一样:

= serializers.IntegerField() username== sss=serializers.CharField(source=) gp=serializers.CharField(source==serializers.SerializerMethodField() get_rl(self,obj): =obj.roles.all().values()
    <span style="color: #0000ff;"&gt;return</span> list(roles)  <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;返回的结果一定有道是json可序列化的对象</span>
<span style="color: #0000ff;"&gt;class</span><span style="color: #000000;"&gt; Meta:
    model </span>=<span style="color: #000000;"&gt; models.UserInfo
    fields </span>= [<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;id</span><span style="color: #800000;"&gt;'</span>,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;username</span><span style="color: #800000;"&gt;'</span>,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;password</span><span style="color: #800000;"&gt;'</span>,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;sss</span><span style="color: #800000;"&gt;'</span>,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;rl</span><span style="color: #800000;"&gt;'</span>,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;gp</span><span style="color: #800000;"&gt;'</span>] <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;配置要序列化的字段</span>
    <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; 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;"&gt;class</span><span style="color: #000000;"&gt; Meta: model </span>=<span style="color: #000000;"&gt; models.UserInfo </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;fields = "__all__" # 使用model中所有的字段</span> fields = [<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;id</span><span style="color: #800000;"&gt;'</span>,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;group</span><span style="color: #800000;"&gt;'</span>,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;roles</span><span style="color: #800000;"&gt;'</span>] <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; 配置要序列化的字段</span> depth = 1 <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;系列化深度,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

urlpatterns =</span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; url(r'^api/v1/auth',url(r</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;^api/v1/group/(?P<xxx>\d+)</span><span style="color: #800000;"&gt;'</span>,views.GroupView.as_view(),name=<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;gp</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;),<span style="color: #ff6600;"&gt;# 新加入组url </span></span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; url(r'^api/(?P<version>[v1|v2]+)/user',</span>

]

views.py

=serializers.HyperlinkedIdentityField(view_name=,lookup_field=,lookup_url_kwarg= = fields = [,,] depth = 1 get(self,many=True,context={: request}) HttpResponse(json.dumps(res.data,ensure_ascii=<span style="color: #0000ff;">class<span style="color: #000000;"> UserGroupSerializer(serializers.ModelSerializer):
<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;"&gt;'</span><span style="color: #800000;"&gt;xxx</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;)
    group_obj</span>=models.UserGroup.objects.get(id=<span style="color: #000000;"&gt;group_id)
    res</span>=UserGroupSerializer(instance=group_obj,many=False) <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;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.类的基本知识
  • 类是实例化之前会执行__new__方法,用于控制一个类生成实例的过程

  • 子类没有__new__方法执行父类的__new__方法
  • __new__方法执行完以后执行__init__构造方法

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;"&gt;"""</span> <span style="color: #0000ff;"&gt;def</span> <span style="color: #800080;"&gt;__init__</span>(self,instance=None,data=empty,**<span style="color: #000000;"&gt;kwargs): <span style="color: #ff6600;"&gt;# many=False后执行的构造方法</span> self.instance </span>=<span style="color: #000000;"&gt; instance </span><span style="color: #0000ff;"&gt;if</span> data <span style="color: #0000ff;"&gt;is</span> <span style="color: #0000ff;"&gt;not</span><span style="color: #000000;"&gt; empty: self.initial_data </span>=<span style="color: #000000;"&gt; data self.partial </span>= kwargs.pop(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;partial</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,False) self._context </span>= kwargs.pop(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;context</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,{}) kwargs.pop(</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;many</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,None) super(BaseSerializer,self).</span><span style="color: #800080;"&gt;__init__</span>(**<span style="color: #000000;"&gt;kwargs) </span><span style="color: #0000ff;"&gt;def</span> <span style="color: #800080;"&gt;__new__</span>(cls,**<span style="color: #000000;"&gt;kwargs): </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; We override this method in order to automagically create</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; `ListSerializer` classes instead when `many=True` is set.</span> <span style="color: #0000ff;"&gt;if</span> kwargs.pop(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;many</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,False): <span style="color: #ff6600;"&gt;# many参数,如果有则执行cls.many_init,没有则执行super(BaseSerializer).__new__ </span></span><span style="color: #0000ff;"&gt;return</span> cls.many_init(*args,**<span style="color: #000000;"&gt;kwargs) <span style="color: #ff6600;"&gt;# many=True,表示对QuerySet进行处理,走该逻辑, </span></span><span style="color: #0000ff;"&gt;return</span> super(BaseSerializer,cls).<span style="color: #800080;"&gt;__new__</span>(cls,**kwargs)<span style="color: #ff6600;"&gt; # many = False ,表示对单独的对象进行处理</span></pre>

执行玩__new__方法接着执行__init__构造方法,此时有根据many值不同执行不同的构造方法,当many=True时候执行cls.many_init方法,

many_init(cls,** Note that we're over-cautious 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;"&gt;"""</span><span style="color: #000000;"&gt; allow_empty </span>= kwargs.pop(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;allow_empty</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,None) child_serializer </span>= cls(*args,**<span style="color: #000000;"&gt;kwargs) list_kwargs </span>=<span style="color: #000000;"&gt; { </span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;child</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;: child_serializer,} </span><span style="color: #0000ff;"&gt;if</span> allow_empty <span style="color: #0000ff;"&gt;is</span> <span style="color: #0000ff;"&gt;not</span><span style="color: #000000;"&gt; None: list_kwargs[</span><span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;allow_empty</span><span style="color: #800000;"&gt;'</span>] =<span style="color: #000000;"&gt; allow_empty list_kwargs.update({ key: value </span><span style="color: #0000ff;"&gt;for</span> key,value <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; kwargs.items() </span><span style="color: #0000ff;"&gt;if</span> key <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; LIST_SERIALIZER_KWARGS }) meta </span>= getattr(cls,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;Meta</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,None) list_serializer_class </span>= getattr(meta,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;list_serializer_class</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,ListSerializer) </span><span style="color: #0000ff;"&gt;return</span> list_serializer_class(*args,**list_kwargs) <span style="color: #ff6600;"&gt;# 最后使用ListSerializer进行实例化</span></pre>

从上面源码中我们知道,对于单独的对象,采用的是Serializer类进行处理,若对象是QuerySet类型(多个对象列表),采用LIstSeriallizer处理,此时我们调用对象的data属性获取结果(示例中这使用的是res.data),下面是源码(寻找时候先从子类找,无该属性就去父类找):

= ReturnDict(ret,serializer=self)

 父类BaseSerialize的属性方法data源码:

hasattr(self,) hasattr(self, msg = </span><span style="color: #0000ff;"&gt;if</span> <span style="color: #0000ff;"&gt;not</span> hasattr(self,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;_data</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;): </span><span style="color: #0000ff;"&gt;if</span> self.instance <span style="color: #0000ff;"&gt;is</span> <span style="color: #0000ff;"&gt;not</span> None <span style="color: #0000ff;"&gt;and</span> <span style="color: #0000ff;"&gt;not</span> getattr(self,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;_errors</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,None)<span style="color: #ff6600;"&gt;:# 判断有无错误,无错误进行序列化</span> self._data </span>=<span style="color: #000000;"&gt; self.to_representation(self.instance) <span style="color: #ff6600;"&gt;# 将instance(QuerySet对象)传入,开始序列化 </span></span><span style="color: #0000ff;"&gt;elif</span> hasattr(self,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;_validated_data</span><span style="color: #800000;"&gt;'</span>) <span style="color: #0000ff;"&gt;and</span> <span style="color: #0000ff;"&gt;not</span> getattr(self,None): self._data </span>=<span style="color: #000000;"&gt; self.to_representation(self.validated_data) </span></pre>
= self._data

从以上源码中可以看出,序列化方法是通过调用类的self.to_representation方法进行序列化,下面我们看Serializer类的to_representation方法

Dict of primitive datatypes. = fields = </span><span style="color: #0000ff;"&gt;for</span> field <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; fields: <span style="color: #ff6600;"&gt;# 循环定义的字段,这个字段可以是我们自己定义的,也可以是model中的字段 </span></span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;: attribute </span>=<span style="color: #000000;"&gt; field.get_attribute(instance) <span style="color: #ff6600;"&gt;#调用字段的get_attribute方法(参数是对象),在示例中可以理解为group.get_attribute(group_obj), </span></span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; SkipField: </span><span style="color: #0000ff;"&gt;continue</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; We skip `to_representation` for `None` values so that fields do</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; not have to explicitly deal with that case.</span> <span style="color: #008000;"&gt;#

<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;"&gt;return</span> ret</pre>

以上源码中,调用field.get_attribute(instance)方法获取每个字段的数据,下面是field.get_attribute(instance)源码(在Field中)

self.default = =type(exc).==self.parent..=instance..= type(exc)(msg)

调用get_attribute函数,进一步出来,需要分析self.source_attrs参数,下面是self.source_attrs部分源码:

self.source == == self.source.split()

以上分析self.source_attrs是一个列表(由source参数按点分割而来),继续回到get_attribute函数,下面是其源码:

Also accepts either attribute lookup on objects or dictionary lookups. </span><span style="color: #800000;"&gt;"""</span> <span style="color: #ff6600;"&gt;# attrs:['group','name']或者['get_user_type_display',]</span> <span style="color: #0000ff;"&gt;for</span> attr <span style="color: #0000ff;"&gt;in</span><span style="color: #000000;"&gt; attrs: # 循环列表 </span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;: </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; isinstance(instance,collections.Mapping): <span style="color: #ff6600;"&gt;#若果是model字段映射(DRF的内部字段转化),直接调用model类的</span> instance </span>=<span style="color: #000000;"&gt; instance[attr]<span style="color: #ff6600;"&gt;#重新赋值,此时的instance已经改变 </span></span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;: instance </span>=<span style="color: #000000;"&gt; getattr(instance,attr) <span style="color: #ff6600;"&gt;#否则,使用反射获取结果,如instance=getattr(userinfo_obj,group) </span></span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; ObjectDoesNotExist: </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; None </span><span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; is_simple_callable(instance): <span style="color: #ff6600;"&gt;#判断是否是可执行,此时如我们示例中的get_user_type_display,其判断过程在类似下面TIPS中,这里不再做过多说明 </span></span><span style="color: #0000ff;"&gt;try</span><span style="color: #000000;"&gt;: instance </span>=<span style="color: #000000;"&gt; instance() <span style="color: #ff6600;"&gt;#重新赋值,加括号进行执行 </span></span><span style="color: #0000ff;"&gt;except</span><span style="color: #000000;"&gt; (AttributeError,KeyError) as exc: </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; If we raised an Attribute or KeyError here it'd get treated</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; as an omitted field in `Field.get_attribute()`. Instead we</span> <span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt; raise a ValueError to ensure the exception is not masked.</span> <span style="color: #0000ff;"&gt;raise</span> ValueError(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;Exception raised in callable attribute "{0}"; original exception was: {1}</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;.format(attr,exc)) </span><span style="color: #0000ff;"&gt;return</span> instance</pre>

TIPS:判断是否是可执行方法

<span style="color: #0000ff;">def<span style="color: #000000;"> func(arg):
<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对象特性,利用反射或者方法进行序列化。

1.基本验证

DRF的数据验证功能与django的form有点类似,示例:获取数据使用的是全局配置的json解析器,在中已经介绍:

=serializers.IntegerField(error_messages={:=serializers.CharField(error_messages={: get(self,ensure_ascii=</span><span style="color: #0000ff;"&gt;def</span> post(self,**<span style="color: #000000;"&gt;kwargs): ret</span>=CheckGroupData(data=request.data)<span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;这里配置了全局json解析器,使用request.data直接获取数据</span> <span style="color: #0000ff;"&gt;if</span><span style="color: #000000;"&gt; ret.is_valid(): </span><span style="color: #0000ff;"&gt;print</span><span style="color: #000000;"&gt;(ret.validated_data) </span><span style="color: #008000;"&gt;#</span><span style="color: #008000;"&gt;获取某个字段数据ret.validated_data.get('name')</span> <span style="color: #0000ff;"&gt;return</span> HttpResponse(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;数据验证成功</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;) </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;: </span><span style="color: #0000ff;"&gt;print</span><span style="color: #000000;"&gt;(ret.errors) </span><span style="color: #0000ff;"&gt;return</span> HttpResponse(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;数据验证失败</span><span style="color: #800000;"&gt;'</span>)</pre>

使用postman向http://127.0.0.1:8000/api/v1/group/1,发送json数据,结果如下:

后台结果:

验证流程生效。

2.自定义验证

和django form功能一样,DRF序列化支持自定义数据验证,示例:

=</span><span style="color: #0000ff;"&gt;def</span> <span style="color: #800080;"&gt;__call__</span><span style="color: #000000;"&gt;(self,value): <span style="color: #ff6600;"&gt;#value是字段值,默认传递 </span></span><span style="color: #0000ff;"&gt;if</span> value == <span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;wd</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;: message </span>= <span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;关键字%s不能是%s</span><span style="color: #800000;"&gt;"</span>%<span style="color: #000000;"&gt;(self.base,value) </span><span style="color: #0000ff;"&gt;raise</span><span style="color: #000000;"&gt; 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(钩子验证方法)

validate_字段名称钩子方法验证示例:

=</span><span style="color: #0000ff;"&gt;def</span><span style="color: #000000;"&gt; validate_name(self,value):<span style="color: #ff6600;"&gt; # 验证的字段值 </span></span><span style="color: #0000ff;"&gt;if</span> value.startswith(<span style="color: #800000;"&gt;"</span><span style="color: #800000;"&gt;w</span><span style="color: #800000;"&gt;"</span><span style="color: #000000;"&gt;): </span><span style="color: #0000ff;"&gt;raise</span> serializers.ValidationError(<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;name字段不能以w开头</span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;) </span><span style="color: #0000ff;"&gt;else</span><span style="color: #000000;"&gt;: </span><span style="color: #0000ff;"&gt;return</span><span style="color: #000000;"&gt; value <span style="color: #ff6600;"&gt;#注意通过验证,必须返回其值

<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"}进行验证,结果如下:

相关文章

注:所有源代码均实测运行过。所有源代码均已上传CSDN,请有...
继承APIView和ViewSetMixin;作用也与APIView基本类似,提供...
一、Django介绍Python下有许多款不同的 Web 框架。Django是重...
本文从nginx快速掌握到使用,gunicorn快速掌握到使用,实现小...
uniapp微信小程序订阅消息发送服务通知
Django终端打印SQL语句 1 Setting配置: 2 默认python 使用的...