在开发REST API接口时,视图中做的最主要有三件事:
(1)将请求的数据(如JSON格式)转换为模型类对象
(2)操作数据库
(3)将模型类对象转换为响应的数据(如JSON格式)
(1)维基百科中对于序列化的定义:
序列化(serialization)在计算机科学的资料处理中,是指将数据结构或物件状态转换成可取用格式(例如存成档案,存于缓冲,或经由网络中传送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。依照序列化格式重新获取字节的结果时,可以利用它来产生与原始物件相同语义的副本。对于许多物件,像是使用大量参照的复杂物件,这种序列化重建的过程并不容易。面向对象中的物件序列化,并不概括之前原始物件所关联的函式。这种过程也称为物件编组(marshalling)。从一系列字节提取数据结构的反向操作,是反序列化(也称为解编组, deserialization, unmarshalling)。
(2)序列化在计算机科学中通常有以下定义:
在数据储存与传送的部分是指将一个对象)存储至一个储存媒介,例如档案或是记亿体缓冲等,或者透过网络传送资料时进行编码的过程,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象)。这程序被应用在不同应用程序之间传送对象),以及服务器将对象)储存到档案或数据库。相反的过程又称为反序列化。
简而言之,我们可以将序列化理解为:
将程序中的一个数据结构类型转换为其他格式(字典、JSON、XML等),例如将Django中的模型类对象装换为JSON字符串,这个转换过程我们称为序列化。
反之,将其他格式(字典、JSON、XML等)转换为程序中的数据,例如将JSON字符串转换为Django中的模型类对象,这个过程我们称为反序列化。
所以在开发REST API时,视图中要频繁的进行序列化与反序列化的编写。
总结:
在开发REST API接口时,我们在视图中需要做的最核心的事是:
(1)将数据库数据序列化为前端所需要的格式,并返回;
(2)将前端发送的数据反序列化为模型类对象,并保存到数据库中。
Django REST framework是一个建立在Django基础之上的Web 应用开发框架,可以快速的开发REST API接口应用。在REST framework中,提供了序列化器Serialzier的定义,可以帮助我们简化序列化与反序列化的过程,不仅如此,还提供丰富的类视图、扩展类、视图集来简化视图的编写工作。REST framework还提供了认证、权限、限流、过滤、分页、接口文档等功能支持。REST framework提供了一个API 的Web可视化界面来方便查看测试接口。
DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。(若没有Django环境,需要先创建环境安装Django)
(1)安装DRF
pip install djangorestframework
(2)添加rest_framework
在settings.py的INSTALLED_APPS中添加:
INSTALLED_APPS = [
...
'rest_framework',
]
a. 定义类,继承自Serializer
b. 和模型类,字段名字一样
c. 和模型类,字段类型一样
d. 和模型类,字段选项一样
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
例如,我们已有了一个数据库模型类BookInfo:
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期')
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
我们想为这个模型类提供一个序列化器,可以定义如下:
from rest_framework import serializers
class BookInfoSerializer(serializers.Serializer):
# read_only=True: 只读; label:字段说明信息
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
bpub_date = serializers.DateField(label='发布日期')
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
注意:serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。serializer是独立于数据库之外的存在。
常用字段类型:
字段 | 字段构造方式 |
---|---|
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=, min_length=None, max_length=None) |
DictField | DictField(child=) |
选项参数:
参数名称 | 作用 |
---|---|
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的构造方法为:
Serializer(instance=None, data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
serializer = AccountSerializer(account, context={'request': request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
我们在django shell中来学习序列化器的使用。
python manage.py shell
from Book.models import BookInfo
from Book.serializers import BookInfoSerializer
# 1.先获取书籍对象
book = BookInfo.objects.get(id=3)
# 2.创建序列化器,instance:表示要序列化的对象
serializer = BookInfoSerializer(instance=book)
# 3.转换数据
print(serializer.data)
注意:
1)instance=book:表示将book进行序列化操作
2)serializer.data:取到序列化的结果
# 1.先获取书籍对象
books = BookInfo.objects.all()
# 2.创建序列化器,instance:表示要序列化的对象,many=True:表示序列化多个对象
serializer = BookInfoSerializer(instance=books,many=True)
# 3.转换数据
print(serializer.data)
如果需要序列化的数据中包含有其他关联对象,则对关联对象数据的序列化需要指明。
例如,在定义英雄数据的序列化器时,外键hbook(即所属的图书)字段如何序列化?
HeroInfo模型类:
#定义英雄模型类HeroInfo
class HeroInfo(models.Model):
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
hname = models.CharField(max_length=20, verbose_name='名称')
hgender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别')
hcomment = models.CharField(max_length=200, null=True, verbose_name='描述信息')
hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 外键
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除')
我们先定义HeroInfoSerialzier除外键字段外的其他部分:
class HeroInfoSerializer(serializers.Serializer):
"""英雄数据序列化器"""
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
id = serializers.IntegerField(label='ID', read_only=True)
hname = serializers.CharField(label='名字', max_length=20)
hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
hcomment = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)
在shell中运行:
from Book.models import HeroInfo
from Book.serializers import HeroInfoSerializer
# 1.先获取英雄对象
hero = HeroInfo.objects.get(id=6)
# 2.创建序列化器,instance:表示要序列化的对象
serializer = HeroInfoSerializer(instance=hero)
# 3.转换数据
print(serializer.data)
运行结果:
上面是定义HeroInfoSerialzier除外键字段外的其他部分,那么如果关联到外键呢???
1)PrimaryKeyRelatedField
此字段将被序列化为关联对象的主键
class HeroInfoSerializer(serializers.Serializer):
"""英雄数据序列化器"""
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
id = serializers.IntegerField(label='ID', read_only=True)
hname = serializers.CharField(label='名字', max_length=20)
hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
hcomment = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)
# 1.关联书籍,主键(PrimaryKeyRelatedField),read_only=True:表示只读,或者设置queryset
hbook = serializers.PrimaryKeyRelatedField(read_only=True)
# hbook = serializers.PrimaryKeyRelatedField(queryset=BookInfo.objects.all())
注意:
指明字段时需要包含read_only=True或者queryset参数:
包含read_only=True参数时,该字段将不能用作反序列化使用
2) StringRelatedField
此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
class HeroInfoSerializer(serializers.Serializer):
"""英雄数据序列化器"""
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
id = serializers.IntegerField(label='ID', read_only=True)
hname = serializers.CharField(label='名字', max_length=20)
hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
hcomment = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)
# 2.关联书籍,使用模型类,__str__方法返回值
hbook = serializers.StringRelatedField(read_only=True)
class HeroInfoSerializer(serializers.Serializer):
"""英雄数据序列化器"""
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
id = serializers.IntegerField(label='ID', read_only=True)
hname = serializers.CharField(label='名字', max_length=20)
hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False)
hcomment = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True)
# 3.关联,书籍序列化器
hbook = BookInfoSerializer()
如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数即可。
在BookInfoSerializer中添加关联字段:
class BookInfoSerializer(serializers.Serializer):
# read_only=True: 只读; label:字段说明信息
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
bpub_date = serializers.DateField(label='发布日期')
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
# 1.关联英雄,主键,在一方中,输出多方内容的时候加上many=True
heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True,many=True)
在shell中运行:
from Book.models import BookInfo
from Book.serializers import BookInfoSerializer
# 1.先获取书籍对象
book = BookInfo.objects.get(id=3)
# 2.创建序列化器,instance:表示要序列化的对象
serializer = BookInfoSerializer(instance=book)
# 3.转换数据
print(serializer.data)
class BookInfoSerializer(serializers.Serializer):
# read_only=True: 只读; label:字段说明信息
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
bpub_date = serializers.DateField(label='发布日期')
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
# 2.关联英雄,__str__返回值
heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
校验内容:
a)数据类型校验 b)字段选项校验 c)单字段校验(方法) d)多字段校验(方法) e)自定义校验(方法)
通过构造序列化器对象,并将要反序列化的数据传递给data构造参数,进而进行验证
1)数据类型校验
需求:验证bread数据类型
view.py:
# 1.准备数据
book_dict = {
"btitle":"源自传",
"bpub_date":"2020-02-20",
"bread":'yfater',
"bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
# 3.输出
print(serializer.data)
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
运行结果:
上面的是因为bread数据类型不符合,报错
修改正确后,运行结果:
2)字段选项校验
需求:验证书名字段长度
view.py:
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
'btitle':'源传',
'bpub_date':'2020-02-20',
'bread':10,
'bcomment':5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
# 3.输出
print(serializer.data)
运行结果:
上面的是因为书名字段选项不符合,报错
修改正确后,运行结果:
当我们忽略一些必要字段时:
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"源自传",
# "bpub_date":"2020-02-20",
# "bread":10,
# "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
# 3.输出
print(serializer.data)
bpub_date = serializers.DateField(label='发布日期',required=False)
requred:默认就是True,必须要传递,除非设置了default | false | read_only
3)单字段校验
需求:验证书名中是否包含金瓶
serializers.py:
class BookInfoSerializer(serializers.Serializer):
# read_only=True: 只读; label:字段说明信息
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
bpub_date = serializers.DateField(label='发布日期',required=False)
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
# 单字段校验
def validate_btitle(self, value):
'''
:param value: 就是传入的btitle
:return:
'''
# 校验value中的内容
if '金瓶' not in value:
raise serializers.ValidationError('书籍名不包含金瓶')
return value
view.py:
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"源自传",
# "bpub_date":"2020-02-20",
# "bread":10,
# "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"金瓶2",
# "bpub_date":"2020-02-20",
# "bread":10,
# "bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
注意:
格式固定:
def vaildate_字段名字(self.value):
pass
4)多个字段校验
需求:阅读量要大于评论量
serializer.py:
class BookInfoSerializer(serializers.Serializer):
# read_only=True: 只读; label:字段说明信息
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
bpub_date = serializers.DateField(label='发布日期')
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
# 2.多字段校验
def validate(self, attrs):
'''
:param attrs: 就是外界传进来的,book_dict
:return:
'''
# 获取阅读量,评论量
bread = attrs['bread']
bcomment = attrs['bcomment']
# 判断
if bcomment > bread:
raise serializers.ValidationError('评论量大于了阅读量')
# 返回
return attrs
views.py:
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"源自传",
"bpub_date":"2020-02-20",
"bread":10,
"bcomment":50
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"源自传",
"bpub_date":"2020-02-20",
"bread":10,
"bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
说明:
单个字段校验时,也可以使用多个字段校验的方法来进行验证
校验不通过的时候一定要抛出异常
5)自定义校验方法
需求:书籍的年份需要大于19年的
serializers.py:
# 自定义校验方法
def check_bpub_date(value):
if value.year < 2019:
raise serializers.ValidationError('书籍的年份需要大于19年的')
return value
# 定义书籍序列化器
class BookInfoSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
# validators=[check_bpub_date]:将自定义的校验方法作用到字段中
bpub_date = serializers.DateField(label='发布日期',validators=[check_bpub_date])
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
view.py:
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"源自传",
"bpub_date":"2020-02-20",
"bread":10,
"bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
如果在验证成功后,想要基于validated_data完成数据对象的创建,可以通过实现create()和update()两个方法来实现。
1)保存对象(create)
view.py:
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"源自传",
"bpub_date":"2020-02-20",
"bread":10,
"bcomment":5
}
# 2.创建序列化器,校验
serializer = BookInfoSerializer(data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
# 3.入库(保存数据)
serializer.save()
运行结果:
报错的原因是,当调用序列化器save方法的时候,必须在序列化器中实现create方法,实现数据入库
serializers.py:
# 自定义校验方法
def check_bpub_date(value):
if value.year < 2019:
raise serializers.ValidationError('书籍的年份需要大于19年的')
return value
# 定义书籍序列化器
class BookInfoSerializer(serializers.Serializer):
# read_only=True: 只读; label:字段说明信息
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
bpub_date = serializers.DateField(label='发布日期',validators=[check_bpub_date])
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
# 实现create方法
def create(self, validated_data):
'''
:param validated_data: 校验成功之后的数据
:return:
'''
# 创建book对象,设置属性,入库
book = BookInfo.objects.create(**validated_data)
# 返回
return book
注意:当使用序列化器调用save方法的时候,执行的就是序列化器中的create方法
2)更新对象(update)
view.py:
from Book.models import BookInfo
from Book.serializers import BookInfoSerializer
# 1.准备数据
book_dict = {
"btitle":"源自传2",
"bpub_date":"2020-03-22",
"bread":100,
"bcomment":50
}
book = BookInfo.objects.get(pk=10)
# 2.创建序列化器,校验
serializer = BookInfoSerializer(instance=book,data=book_dict)
# raise_exception=True:校验不通过时,会报错
serializer.is_valid(raise_exception=True)
# 3.入库(保存数据)
serializer.save()
报错原因是,当在序列化器中传递了两个属性instance,data,同时在使用序列化器调用了save方法,则需要重写序列化器中的update方法。
serializers.py:
# 自定义校验方法
def check_bpub_date(value):
if value.year < 2019:
raise serializers.ValidationError('书籍的年份需要大于19年的')
return value
# 定义书籍序列化器
class BookInfoSerializer(serializers.Serializer):
# read_only=True: 只读; label:字段说明信息
id = serializers.IntegerField(read_only=True,label='书籍编号')
btitle = serializers.CharField(max_length=20,min_length=3,label='名称')
bpub_date = serializers.DateField(label='发布日期',validators=[check_bpub_date])
bread = serializers.IntegerField(default=0,min_value=0,label='阅读量')
bcomment = serializers.IntegerField(default=0,max_value=50,label='评论量')
is_delete = serializers.BooleanField(default=False,label='逻辑删除')
# 实现update方法
def update(self, instance, validated_data):
'''
:param instance: 外界传入的book对象
:param validated_data: 校验成功之后的book_dict数据
:return:
'''
# 更新数据
instance.btitle = validated_data['btitle']
instance.bpub_date = validated_data['bpub_date']
instance.bread = validated_data['bread']
instance.bcomment = validated_data['bcomment']
# 入库
instance.save()
# 返回
return instance
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
serializers.py:
# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo # 参考模型类生成字段
fields = '__all__' # 生成所有字段
在shell中运行打印:
from Book.serializers import BookModelSerializer
BookModelSerializer()
运行结果:
由上我们可以知道ModelSerializer可以参考模型类自动生成字段
思考:如果我们想额外添加字段,该怎么操作???
# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo
class BookModelSerializer(serializers.ModelSerializer):
mobile = serializers.CharField(max_length=11,min_length=11,label='手机号')
class Meta:
model = BookInfo # 参考模型类生成字段
fields = '__all__' # 生成所有字段
运行结果:
所以ModelSerializer可以参考模型类自动生成字段,也可以手动添加字段
view.py:
from Book.models import BookInfo
from Book.serializers import BookModelSerializer
# 1.获取模型类对象
book = BookInfo.objects.get(pk=10)
# 2.创建序列化对象
serializer = BookModelSerializer(instance=book)
# 3.输出结果
print(serializer.data)
运行结果:
之所以报错,是因为刚刚我们手动添加了mobile字段,而原数据库中没有这个字段的数据
解决措施(4种):
a.模型类中添加mobile字段
b.删除序列化器中mobile
c.动态添加一个mobile属性
d.将mobile字段设置为write_only(只写,只进行反序列化)
部分案例:
动态添加一个mobile属性
from Book.models import BookInfo
from Book.serializers import BookModelSerializer
# 1.获取模型类对象
book = BookInfo.objects.get(pk=10)
# 动态添加一个mobile属性
book.mobile = '12121212112'
# 2.创建序列化对象
serializer = BookModelSerializer(instance=book)
# 3.输出结果
print(serializer.data)
运行结果:
将mobile字段设置为write_only
serializers.py:
from rest_framework import serializers
from Book.models import BookInfo
class BookModelSerializer(serializers.ModelSerializer):
# 将mobile字段设置为write_only(只写,只进行反序列化)
mobile = serializers.CharField(max_length=11,min_length=11,label='手机号',write_only=True)
class Meta:
model = BookInfo # 参考模型类生成字段
fields = '__all__' # 生成所有字段
1)入库操作
serializer.py:
# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo # 参考模型类生成字段
fields = '__all__' # 生成所有字段
views.py:
from Book.serializers import BookModelSerializer
# 准备字典数据
book_dict = {
'btitle':'鹿鼎记',
'bpub_date':'2020-9-22',
'bread':10,
'bcomment':5
}
# 序列化器对象创建
serializer = BookModelSerializer(data=book_dict)
# 校验,入库
serializer.is_valid(raise_exception=True)
serializer.save()
运行结果:
由上可发现,我们连create方法都没有创建, 但是却能直接运行成功。
2)更新操作
from Book.serializers import BookModelSerializer
# 准备字典数据,书籍对象
book = BookInfo.objects.get(pk=11)
book_dict = {
'btitle':'鹿鼎记2',
'bpub_date':'2020-10-22',
'bread':199,
'bcomment':50
}
# 序列化器对象创建
serializer = BookModelSerializer(instance=book,data=book_dict)
# 校验,入库
serializer.is_valid(raise_exception=True)
serializer.save()
运行结果:
由上可发现,我们update方法也没有创建, 但是却也能直接运行成功。
以上没有创建方法,但都能运行成功,这是因为ModelSerializer序列化器提供了create方法和update方法
ModelSerializer源码:
ModelSerializer序列化器作用:
1.可以参考模型类自动生成字段,还可以自己编写字段
2.提供了create方法和update方法
使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段
serializers.py:
# 定义书籍模型类序列化器
from rest_framework import serializers
from Book.models import BookInfo
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo # 参考模型类生成字段
# 生成指定的字段
fields = ['id','btitle']
在shell中运行:
from Book.serializers import BookModelSerializer
BookModelSerializer()
可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
serializers.py:
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo # 参考模型类生成字段
# 生成指定的字段
fields = ['id','btitle']
# 设置只读字段
read_only_fields = ['btitle']
使用exclude可以明确排除掉哪些字段
serializers.py:
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = BookInfo # 参考模型类生成字段
# 排除指定的字段
exclude = ['btitle']
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
原字段参数:
class BookModelSerializer(serializers.ModelSerializer):
# mobile = serializers.CharField(max_length=11,min_length=11,label='手机号',write_only=True)
class Meta:
model = BookInfo # 参考模型类生成字段
fields = '__all__' # 生成所有字段
class BookModelSerializer(serializers.ModelSerializer):
# mobile = serializers.CharField(max_length=11,min_length=11,label='手机号',write_only=True)
class Meta:
model = BookInfo # 参考模型类生成字段
fields = '__all__' # 生成所有字段
# 给生成的字段添加额外约束
extra_kwargs = {
'bread':{
'max_value':999999,
'min_value':0
},
'bcomment':{
'max_value':999999,
'min_value':0
}
}