Serializer定义
序列化(Serializer)在计算机科学的资料处理中, 是指将数据结构或物件状态转换成可取用格式(例如存成档案、存于缓存、或经由网络中传送), 以留待后续在相同或另一台计算机环境中, 能恢复原来状态的过程。依照序列化格式重新获取字节的结果时, 可以利用他来产生与原始物件相同语义的副本。对于许多物件, 像是使用大量参考的复杂物件, 这种序列化重建的过程并不容易。面向对象中物件序列化, 并不概括之前原始物件所关联的函式。这种过程也称为物件编组(marshalling)。从一系列字节提取数据结构的反向操作, 是反序列化(也称为解编组, deserialization, unmarshalling)
序列化在计算机科学中通常有如下定义:
在数据存储与传送的部分是指将一个对象存储至一个储存媒介, 例如档案或记忆体缓冲等, 或者通过网络传送资料时进行编码的过程, 可以是字节或XML等格式。而字节的或是XML编码格式可以还原完全相同的对象。这程序被应用不同应用程序之间传送对象, 以及服务器将对象存储到档案或数据库。相反的过程又称之为反序列化
简而言之, 可以将序列化理解为:
将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等), 例如将Django中的模型类对象转换成JSON字符串, 这个转换过程称之为序列化
反之, 将其他格式(字典、JSON、XML等)转换为程序中的数据, 例如将JSON字符串转换成Django中的模型类对象, 这个过程我们称之为反序列化
DRF框架之序列化组件
Serializer(偏底层)
ModelSerializer(重点)
ListModelSerializer(辅助群改)
序列化器的基本使用
1. 在app中创建seralizers.py文件
2. 定义序列化器类(字段名必须和模型中的字段保存一致, 否则会出错)
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer
class BookInfoSerializer(serializers.Serializer): id = serializers.IntegerField(label='id', read_only=True) name = serializers.CharField(max_length=20, label='名称') pub_date = serializers.DateField(label='发布日期') readcount = serializers.IntegerField(default=0, label='阅读量') commentcount = serializers.IntegerField(default=0, label='评论量') is_delete = serializers.BooleanField(default=False, label='逻辑删除')
# 序列化提供给前台的字段个数由后台决定, 可以少提供, 但是提供的数据库对应的字段, 名字一定要与数据库字段相同
字段与选项
常用字段类型
字段 | 字段构造方式 |
---|---|
BooleanField | BooleanField() |
NullBooleanField | NullBooleanField() |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3) 'int' - 如: "123456789012312313134124512351145145114" 4) 'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | IntegerField(max_value=None, min_value=None) |
FloatField | FloatField(max_value=None, min_value=None) |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | DurationField() |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | MultipleChoiceField(choices) |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | ListField(child=<a_field_instance>, min_length=None, max_length=None) |
DictField | DictField(child=<a_field_instance>) |
选项参数
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
min_value | 最大值 |
通用参数
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
创建Serializer对象
Serializer的构造方法是
Serializer(instance=None, data=empty, **kwargs)
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据
序列化
注意: 使用序列化器对象时, 需要传入待序列化的对象, 返回的是序列化器对象, 并不能作为数据返回
(会报错)
。
将序列化器数据返回可以调用序列化器的data属性返回。如果返回的是多个模型对象, 那么需要在使用序列化器的时候传入参数many=True
基本使用
from booktest.serializer import BookInfoSerializer, HeroInfoSerializer from booktest.models import BookInfo, PeopleInfo """ 1. 序列化器, 序列化单个书籍对象 """ # 1. 获取书籍对象 book = BookInfo.objects.get(id=1) # 2. 创建序列化器, instance: 表示要序列化的对象 serializer = BookInfoSerializer(instance=book) # 3. 转换数据 print(serializer.data) """ 2. 序列化器, 序列化列表书籍对象 """ # 1. 获取书籍对象 book = BookInfo.objects.all() # 2. 创建序列化器, instance: 表示要序列化的对象, many=True表示序列化多个对象 serializer = BookInfoSerializer(instance=book, many=True) # 3. 转换数据 print(serializer.data)
关联对象嵌套序列化
如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。
PrimaryKeyRelatedField
此字段将被序列化为关联对象的主键。
book = serializers.PrimaryKeyRelatedField(read_only=True)
注意: 指明字段时需要包含read_only=True或者queryset参数, 否则会报错
包含read_only=True参数时,该字段将不能用作反序列化使用
book = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())
StringRelatedField
PrimaryKeyRelatedField字段只会返回关联对象的主键id, 如果需要返回name等信息的时候
而StringRelatedField字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
book = serializers.StringRelatedField(read_only=True)
使用关联对象的序列化器
book = BookInfoSerializer()
使用many参数
如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数即可。
peopleinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
反序列化
反序列化基本使用
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
# 1. 获取前台传入的数据 request_data = request.data # 2. 数据类型合法, 但数据内容不一定合法, 需要校验数据, 校验(参与反序列化)的数据需要赋值给data book_serializer = serializers.UserDeSerializer(data = request_data) # 3. 使用序列化对象调用is_valid()完成校验 book_serializer.is_valid() # 4. 校验失败的信息都会被缓存在序列化对象.errors里面 book_serializer.errors # 5. 校验成功, 使用save()方法将数据保存 book_serializer.save()
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
# 1. 准备数据 book_dict = { "name": "求魔", "pub_date": "2016-09-18", "readcount": 10, "commentcount": 5 } # 2. 创建序列化器, 校验 serializer = BookInfoSerializer(data=book_dict) serializer.is_valid(raise_exception=True) # 校验不通过,报错 # 3. 输出 print(serializer.data)
字段校验
1.
name = serializers.CharField( max_length=64, min_length=3, error_messages={ 'max_length': '名称过长', 'min_length': '名称过短', } ) phone = serializers.CharField(required=False)
max_length
: 最长长度
min_length
: 最段长度
error_messages
: 自定义异常
requried
: 是否必传
2. 局部校验钩子: validate_要校验的字段名(self, 当前要校验字段的值)
# 校验规则: 校验通过返回原值, 校验失败, 抛出异常 def validate_name(self, value): # print('value', value) if 'j' in value.lower(): raise exceptions.ValidationError({'name': '名字非法'}) return value
3.
def validate(self, attrs): # print('attrs', attrs) pwd = attrs.get('pwd') re_pwd = attrs.pop('re_pwd') if pwd != re_pwd: raise exceptions.ValidationError({'pwd': '两次密码不一致'}) return attrs
4. 自定义校验规则
def check_pub_date(value): if value.year < 2018: raise serializers.ValidationError('书籍的年份需要大于2018年') return value class BookInfoSerializer(serializers.Serializer): pub_date = serializers.DateField(label='发布日期', validators=[check_pub_date])
保存数据
如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个方法来实现。
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参数获取到
# request.user是django中记录登录用户的模型类对象 serializer.save(owner=request.user)2) 默认序列化器必须传递所有required的字段, 否则会抛出异常。但是可以使用partial参数来允许部分字段更新
serializer = CommentSerializer(comment, data={'content': u"foo bar"}, partial=True)