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

前端之家收集整理的这篇文章主要介绍了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;#<a href="/tag/yonghu/" target="_blank" class="keywords">用户</a>信息
</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() 提取的序列化字段,名称和model中定义的字段相同 username==方法只能拿到user_type的ID sss=serializers.CharField(source=) 自定义字段名称,和数据模型不一致,需要指定source本质调用get_user_type_display()方法获取数据 gp=serializers.CharField(source==serializers.SerializerMethodField() 方法一 get_rl(self,obj): 名称固定:get_定义的字段名称 自定义序列化 :param obj:传递的model对象,这里已经封装好的 :return: =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; <a href="/tag/Meta/" target="_blank" class="keywords">Meta</a>:
    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; <a href="/tag/Meta/" target="_blank" class="keywords">Meta</a>: 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= 名称,也就是kwargs中的key Meta: model = fields = [,,] depth = 1 用户信息 get(self,many=True,context={: request}) 生成超链接字段,则需要加context={'request': 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.类的基本知识

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<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;"&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-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;"&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 }) <a href="/tag/Meta/" target="_blank" class="keywords">Meta</a> </span>= getattr(cls,<span style="color: #800000;"&gt;'</span><span style="color: #800000;"&gt;<a href="/tag/Meta/" target="_blank" class="keywords">Meta</a></span><span style="color: #800000;"&gt;'</span><span style="color: #000000;"&gt;,None) list_serializer_class </span>= getattr(<a href="/tag/Meta/" target="_blank" class="keywords">Meta</a>,<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),下面是源码(寻找时候先从子类找,无该属性就去父类找):

=父类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;:# 判断有无<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;"&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;#<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;"&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,是一个函数,并不是类方法。        self.source_attrs:以'.'分割的列表,会被使用为反射获取属性 self.default required: = =type(exc).==self.parent..=instance..= type(exc)(msg)

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

self.source == == self.source.split() 自定义字段传入的source参数,如:gp=serializers.CharField(source='group.name'),sss=serializers.CharField(source='get_user_type_display')

以上分析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的内部字段转化),直接<a href="/tag/diaoyong/" target="_blank" class="keywords">调用</a>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;#否则,使用反射<a href="/tag/huoqu/" target="_blank" class="keywords">获取</a>结果,如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={required:=serializers.CharField(error_messages={required: 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直接<a href="/tag/huoqu/" target="_blank" class="keywords">获取</a>数据</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;<a href="/tag/huoqu/" target="_blank" class="keywords">获取</a>某个字段数据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"}进行验证,结果如下:

猜你在找的Django相关文章