三、反序列化使用

3.1 验证

使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。

验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。

验证成功,可以通过序列化器对象的validated_data属性获取数据。

在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。

如我们前面定义过的BookInfoSerializer

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', max_length=20)
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)

通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证

from booktest.serializers import BookInfoSerializer
data = {'bpub_date': 123}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # 返回False
serializer.errors
# {'btitle': [ErrorDetail(string='This field is required.', code='required')], 'bpub_date': [ErrorDetail(string='Date has wrong format. Use one of these formats instead: YYYY[-MM[-DD]].', code='invalid')]}
serializer.validated_data # {} data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.errors # {}
serializer.validated_data # OrderedDict([('btitle', 'python')])

is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。

# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)

如果觉得这些还不够,需要再补充定义验证行为,可以使用以下三种方法:

3.1.1)validators

在字段中添加validators选项参数,也可以补充验证行为,如

def about_django(value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的") class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)

测试:

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}

3.1.2)validate_<field_name>

<field_name>字段进行验证,如

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
... def validate_btitle(self, value):
if 'django' not in value.lower():
raise serializers.ValidationError("图书不是关于Django的")
return value

测试

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'python'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # False
serializer.errors
# {'btitle': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}

3.1.3)validate

在序列化器中需要同时对多个字段进行比较验证时,可以定义validate方法来验证,如

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
... def validate(self, attrs):
bread = attrs['bread']
bcomment = attrs['bcomment']
if bread < bcomment:
raise serializers.ValidationError('阅读量小于评论量')
return attrs

测试

from booktest.serializers import BookInfoSerializer
data = {'btitle': 'about django', 'bread': 10, 'bcomment': 20}
s = BookInfoSerializer(data=data)
s.is_valid() # False
s.errors
# {'non_field_errors': [ErrorDetail(string='阅读量小于评论量', code='invalid')]}

REST framework提供的validators:

  • UniqueValidator

    单字段唯一,如

    from rest_framework.validators import UniqueValidator
    
    slug = SlugField(
    max_length=100,
    validators=[UniqueValidator(queryset=BlogPost.objects.all())]
    )
  • UniqueTogetherValidation

    联合唯一,如

    from rest_framework.validators import UniqueTogetherValidator
    
    class ExampleSerializer(serializers.Serializer):
    # ...
    class Meta:
    validators = [
    UniqueTogetherValidator(
    queryset=ToDoItem.objects.all(),
    fields=('list', 'position')
    )
    ]

3.2 保存

如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个方法来实现。

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
... def create(self, validated_data):
"""新建"""
return BookInfo(**validated_data) def update(self, instance, validated_data):
"""更新,instance为要更新的对象实例"""
instance.btitle = validated_data.get('btitle', instance.btitle)
instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
instance.bread = validated_data.get('bread', instance.bread)
instance.bcomment = validated_data.get('bcomment', instance.bcomment)
return instance

如果需要在返回数据对象的时候,也将数据保存到数据库中,则可以进行如下修改

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
... def create(self, validated_data):
"""新建"""
return BookInfo.objects.create(**validated_data) def update(self, instance, validated_data):
"""更新,instance为要更新的对象实例"""
instance.btitle = validated_data.get('btitle', instance.btitle)
instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
instance.bread = validated_data.get('bread', instance.bread)
instance.bcomment = validated_data.get('bcomment', instance.bcomment)
instance.save()
return instance

实现了上述两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了

book = serializer.save()

如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。

from db.serializers import BookInfoSerializer
data = {'btitle': '封神演义'}
serializer = BookInfoSerializer(data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: 封神演义> from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天剑'}
serializer = BookInfoSerializer(book, data=data)
serializer.is_valid() # True
serializer.save() # <BookInfo: 倚天剑>
book.btitle # '倚天剑'

两点说明:

1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

serializer.save(owner=request.user)

2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新

# Update `comment` with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

08.DRF-反序列化的更多相关文章

  1. 前后端分离djangorestframework——序列化与反序列化数据

    我们写好后端的代码,要把数据交给前端的展示的,这个数据以什么类型给前端呢?学到这里,我们已经知道这个数据最好是json字符串才行,因为网络间的传输,只认字符串或者二进制,字符串就是我们的数据,二进制就 ...

  2. PHP反序列化链分析

    前言 基本的魔术方法和反序列化漏洞原理这里就不展开了. 给出一些魔术方法的触发条件: __construct()当一个对象创建(new)时被调用,但在unserialize()时是不会自动调用的 __ ...

  3. 『练手』手写一个独立Json算法 JsonHelper

    背景: > 一直使用 Newtonsoft.Json.dll 也算挺稳定的. > 但这个框架也挺闹心的: > 1.影响编译失败:https://www.cnblogs.com/zih ...

  4. drf3 Serializers 序列化组件

    为什么要用序列化组件 做前后端分离的项目,我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式. 给前端数据的时候都要转成json格式,那就需要对从数据库拿到的数据进行序列化. ...

  5. 深度解析Django REST Framework 批量操作

    我们都知道Django rest framework这个库,默认只支持批量查看,不支持批量更新(局部或整体)和批量删除. 下面我们来讨论这个问题,看看如何实现批量更新和删除操作. DRF基本情况 我们 ...

  6. drf序列化与反序列化

    序列化器-Serializer 定义序列化器 Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serial ...

  7. DRF框架(二)——解析模块(parsers)、异常模块(exception_handler)、响应模块(Response)、三大序列化组件介绍、Serializer组件(序列化与反序列化使用)

    解析模块 为什么要配置解析模块 1)drf给我们提供了多种解析数据包方式的解析类 form-data/urlencoded/json 2)我们可以通过配置来控制前台提交的哪些格式的数据后台在解析,哪些 ...

  8. drf序列化器与反序列化

    什么是序列化与反序列化 """ 序列化:对象转换为字符串用于传输 反序列化:字符串转换为对象用于使用 """ drf序列化与反序列化 &qu ...

  9. Django框架深入了解_02(DRF之序列化、反序列化)

    序列化:将Python对象准换成json格式的字符串,反之即为反序列化 DRF的序列化使用过程: 使用drf的序列化组件 -1 新建一个序列化类继承Serializer -2 在类中写要序列化的字段 ...

  10. DRF 序列化组件 序列化的两种方式 反序列化 反序列化的校验

    序列化组件 django自带的有序列化组件不过不可控不建议使用(了解) from django.core import serializers class Books(APIView): def ge ...

随机推荐

  1. Order by 优化

    写在前面 文章涉及到的 customer 表来源于案例库 sakila,下载地址为 http://downloads.mysql.com/docs/sakila-db.zip MySQL 排序方式 通 ...

  2. [Android应用开发] 02.界面展现和文件权限

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  3. C/C++代码优化之求两个整型的平均值

    在 C/C++ 中, 直接利用 (x + y) >> 1 来计算 \(\left\lfloor {\left( {x + y} \right)/2} \right\rfloor\) (两个 ...

  4. 加速国内Github代码下载速度

    标题: 加速国内Github代码下载速度 作者: 梦幻之心星 347369787@QQ.com 标签: [Github, 代码, 下载] 目录: 代码 日期: 2019-10-27 目录 前提说明 解 ...

  5. vue-cli4 + TS构建新项目

    1. 如果你之前没有安装vue-cli,可以通过如下命令进行安装: npm install -g @vue/cli yarn global add @vue/cli 2. 创建vue项目 vue cr ...

  6. 使用PRTG和panabit结合定位网络阻塞的来源

    一.背景   在网络管理工作中,有时会出现网络阻塞,需要定位阻塞来源以采取措施解决问题.二.以一个网络阻塞案例说明定位方法   案例:某企业日常使用多条网络线路,某一段时间发现某条线路传输速率下降,对 ...

  7. Username for 'https://github.com': remote: Invalid username or password. fatal: Authentication failed for 'https://github.com/GLSmile/pythontest.git/' 问题

    使用$ git push -u origin master 进行同步时,提示输入用户名和密码,但是我输入正确的信息后,仍然 会报Username for 'https://github.com': r ...

  8. ecilpse 纠错插件

    在market里面搜索 Spot Bugs Unnecessary Code Detector

  9. Java实现 N的阶乘

    import java.util.Scanner; public class n的阶乘 { public static void main(String[] args) { Scanner sc =n ...

  10. Java实现第九届蓝桥杯第几个幸运数字

    第几个幸运数字 题目描述 到x星球旅行的游客都被发给一个整数,作为游客编号. x星的国王有个怪癖,他只喜欢数字3,5和7. 国王规定,游客的编号如果只含有因子:3,5,7,就可以获得一份奖品. 我们来 ...