【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属性获取。

注意:

  1. 序列化器声明了以后,不会自动执行,需要我们在视图中进行调用才可以。
  2. 序列化器无法直接接收数据,需要我们在视图中创建序列化器对象时,将使用数据传入。
  3. drf提供的视图会帮我们将dict转换成json,或者将客户端传来的数据转为dict

二、序列化对象

序列化器的使用分两个阶段:

  1. 客户端请求时,使用序列化器可以完成对数据的反序列化(write)
  2. 服务器响应时,使用序列化器可以完成对数据的序列化(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)

还是不清楚的可以参考这两篇,个人认为写得很详细:

posted @ 2019-11-20 20:53  fxyadela  阅读(181)  评论(0编辑  收藏  举报