【1120 | Day63】序列化对象和反序列化对象
一、创建序列器对象
定义好Serializer类后,就可以创建Serializer对象了,具体构造方法为:
Serializer(instance=None, data=empty, **kwarg)
参数:
instance:
用于序列化时,将模型类对象传入instance参数 。
data:
用于反序列化时,将要被反序列化的数据传入data参数 。
context:
除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据。
serializer = AccountSerializer(account, context={'request': request})
//通过context参数附加的数据,可以通过Serializer对象的context属性获取。
注意:
- 序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
- 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时,将使用数据传入。
- drf提供的视图会帮我们将
dict
转换成json
,或者将客户端传来的数据转为dict
。
二、序列化对象
序列化器的使用分两个阶段:
- 在客户端请求时,使用序列化器可以完成对数据的反序列化(write)。
- 在服务器响应时,使用序列化器可以完成对数据的序列化(read)。
第一步:
查找对象或对象集
//对象
from booktest.models import BookInfo
book = BookInfo.objects.get(id=2)
//对象集
from booktest.models import BookInfo
book_qs = BookInfo.objects.all()
第二步:
构造序列化器对象
//对象
from booktest.serializers import BookInfoSerializer
serializer = BookInfoSerializer(book)
//对象集
from booktest.serializers import BookInfoSerializer
//如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补
充说明
serializer = BookInfoSerializer(book_qs, many=True)
第三步:
获取序列化数据
//对象
serializer.data
# {'id': 2, 'btitle': '天龙八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40,
'image': None}
//对象集
serializer.data
# [OrderedDict([('id', 2), ('btitle', '天龙八部'), ('bpub_date', '1986-07-24'), ('bread',
36), ('bcomment', 40), ('image', N]), OrderedDict([('id', 3), ('btitle', '笑傲江湖'),
('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80), ('image'ne)]),
OrderedDict([('id', 4), ('btitle', '雪山飞狐'), ('bpub_date', '1987-11-11'), ('bread',
58), ('bcomment', 24), ('ima None)]), OrderedDict([('id', 5), ('btitle', '西游记'),
('bpub_date', '1988-01-01'), ('bread', 10), ('bcomment', 10), ('im',
'booktest/xiyouji.png')])]
三、反序列化对象
流程概述
反序列化是相似的。
- 验证:
is_valid()
该方法带有一个可选
raise_exception
标志,serializers.ValidationError
如果存在验证错误,它将导致引发异常。这些异常由REST框架提供的默认异常处理程序自动处理,并且将HTTP 400 Bad Request
默认返回响应。
-
True
validated_data
-
False
- 字段错误>>>
errors
- 非字段错误>>>
NON_FIELD_ERRORS_KEY
- 字段错误>>>
-
保存
- create( )
- update( )
具体操作
1. 验证
如我们前面定义过的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()
方法还可以在验证失败时抛出异常,通过传递raise_exception=True
参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request
响应
# Return a 400 response if the data was invalid.
serializer.is_valid(raise_exception=True)
2. 保存
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以将数据转成模型类对象
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()
3. 补充
如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create() 被调用
from db.serializers import BookInfoSerializer
data = {'btitle': '封神演义'}
serializer = BookInfoSerializer(data=data) #没有传入instance实例
serializer.is_valid() # True
serializer.save() # <BookInfo: 封神演义>
相反,如果传递了instance实例,则调用save()方法的时候,update()被调用
from db.models import BookInfo
book = BookInfo.objects.get(id=2)
data = {'btitle': '倚天剑'}
serializer = BookInfoSerializer(book, data=data) #传入instance实例book
serializer.is_valid() # True
serializer.save() # <BookInfo: 倚天剑>
book.btitle # '倚天剑'
在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update() 中的validated_data参数获取到
# request.user 是django中记录当前登录用户的模型对象
serializer.save(owner=request.user)
默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用 partial参数来允许部分字段更新
# Update `book` with partial data
serializer = BookInfoSerializer(book, data={'title': u'Python'}, partial=True)
还是不清楚的可以参考这两篇,个人认为写得很详细: