使用serializer之前要先进行环境的安装和配置
- 首先安装DRF
pip install djangorestframework
# DRF是以Django扩展应用的方式提供的,所以我们可以直接利用已有的Django环境而无需从新创建。
#(若没有Django环境,需要先创建环境安装Django)
# DRF需要以下依赖:
# Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
# Django (1.10, 1.11, 2.0)
- 在django项目中注册rest_framework应用
在settings.py的INSTALLED_APPS中添加'rest_framework'
INSTALLED_APPS = [
...
'rest_framework',
]
在django项目中使用serializer序列化器
我们在django项目中新建一个子应用(bookapp)进行serializer序列化器的使用介绍(自己完成子应用的注册和路由配置):
我们在models.py中定义一个书籍模型类BookInfo和英雄模型类HeroInfo:
# 数据导入见附录
class BookInfo(models.Model):
btitle = models.CharField(max_length=20,verbose_name="书籍名称")
bpub_date = models.DateField(null=True,verbose_name="发布日期")
bread = models.IntegerField(default=0,verbose_name="阅读量")
bcomment = models.IntegerField(default=0,verbose_name="评论量")
is_delete = models.BooleanField(default=False,verbose_name="逻辑删除")
class Meta:
db_table = "tb_books" # 表在数据库的名字
verbose_name = "图书" #在admin站点显示名称
verbose_name_plural = verbose_name
def __str__(self):
return self.btitle
class HeroInfo(models.Model):
GENDER_CHOICES = (
(0, 'female'),
(1, 'male')
)
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='逻辑删除')
class Meta:
db_table = 'tb_heros'
verbose_name = '英雄'
verbose_name_plural = verbose_name
def __str__(self):
return self.hname
我们为这两个模型类提供序列化器,可以定义如下:
Django REST framework中的Serializer使用类来定义,须继承自rest_framework.serializers.Serializer。
from rest_framework import serializers
class BookInfoSerializer(serializers.Serializer):
btitle = serializers.CharField(min_length=3,max_length=20)
bpub_date = serializers.DateField()
bread = serializers.IntegerField(read_only=True)
bcomment = serializers.IntegerField(write_only=True)
class HeroInfoSerializer(serializers.Serializer):
hname = serializers.CharField()
hcomment = serializers.CharField()
注意: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 = BookInfoSerializer(instance=None, data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
serializer = BookInfoSerializer(instance=None, data=empty, context={'request': request})
# 通过context参数附加的数据,可以通过Serializer对象的context属性获取。
序列化使用
我们在django shell中来学习序列化器的使用。
python manage.py shell
1 基本使用
1) 先查询出一个图书对象
from bookapp.models import BookInfo
book = BookInfo.objects.get(id=2)
2) 构造序列化器对象
from bookapp.serializers import BookInfoSerializer
serializer = BookInfoSerializer(book)
3)获取序列化数据
# 通过data属性可以获取序列化后的数据,序列化器定义了几个字段就序列化几个字段
serializer.data
# { 'btitle': '天龙八部', 'bpub_date': '1986-07-24', 'bread': 36, 'bcomment': 40}
# 实际开发中直接将序列化后的数据返回给前端开发人员使用
4)如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
serializer.data
# [OrderedDict([('btitle', '天龙八部'), ('bpub_date', '1986-07-24'), ('bread', 36), ('bcomment', 40)], OrderedDict([('btitle', '笑傲江湖'), ('bpub_date', '1995-12-24'), ('bread', 20), ('bcomment', 80)]), OrderedDict([('btitle', '雪山飞狐'), ('bpub_date', '1987-11-11'), ('bread', 58), ('bcomment', 24)]), OrderedDict([('btitle', '西游记'), ('bpub_date', '1988-01-01'), ('bread', 10), ('bcomment', 10)])]
2 关联对象嵌套序列化
对序列化器添加代码:
from rest_framework import serializers
class BookInfoSerializer1(serializers.Serializer):
btitle = serializers.CharField()
bpub_date = serializers.DateField()
class HeroInfoSerializer(serializers.Serializer):
hname = serializers.CharField()
hcomment = serializers.CharField()
# 此字段将被序列化为关联对象的主键。
hbook = serializers.PrimaryKeyRelatedField(read_only=True)
#此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
hbook = serializers.StringRelatedField(read_only=True)
# 使用关联对象的序列化器
hbook = BookInfoSerializer1()
class BookInfoSerializer(serializers.Serializer):
btitle = serializers.CharField(min_length=3,max_length=20)
bpub_date = serializers.DateField()
bread = serializers.IntegerField(read_only=True)
# 此字段将被序列化为关联对象的主键。
heroinfo_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
# 此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)
# 使用关联对象的序列化器
heroinfo_set = HeroInfoSerializer(many=True)
以BookInfoSerializer序列化器的代码进行说明:
1) PrimaryKeyRelatedField:
指明字段时需要包含read_only=True或者queryset参数
# 此字段将被序列化为关联对象的主键。
heroinfo_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
shell中使用效果:
from bookapp.serializers import BookInfoSerializer
from bookapp.models import BookInfo
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
{'bread': 36, 'heroinfo_set': [6, 7, 8, 9], 'bpub_date': '1986-07-24', 'btitle': '天龙八部'}
2) StringRelatedField
# 此字段将被序列化为关联对象的字符串表示方式(即__str__方法的返回值)
heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)
shell中使用效果:
from bookapp.serializers import BookInfoSerializer
from bookapp.models import BookInfo
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
{'heroinfo_set': ['乔峰', '段誉', '虚竹', '王语嫣'], 'btitle': '天龙八部', 'bread': 36, 'bpub_date': '1986-07-24'}
3)使用关联对象的序列化器
# 使用关联对象的序列化器
heroinfo_set = HeroInfoSerializer(many=True)
shell中使用效果:
from bookapp.serializers import BookInfoSerializer
from bookapp.models import BookInfo
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
{'btitle': '天龙八部', 'bread': 36, 'bpub_date': '1986-07-24', 'heroinfo_set': [OrderedDict([('hname', '乔峰'), ('hcomment', '降龙十八掌')]), OrderedDict([('hname', '段誉'), ('hcomment', '六脉神剑')]), OrderedDict([('hname', '虚竹'), ('hcomment', '天山[('hname', '王语嫣'), ('hcomment', '神仙姐姐')])]}
many参数
如果关联的对象数据不是只有一个,而是包含多个数据,如想序列化图书BookInfo数据,每个BookInfo对象关联的英雄HeroInfo对象可能有多个,此时关联字段类型的指明仍可使用上述几种方式,只是在声明关联字段时,多补充一个many=True参数即可。
反序列化使用
1 验证
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
如我们前面定义过的BookInfoSerializer:
btitle = serializers.CharField(min_length=3,max_length=20)
在反序列化时会对btitle的值进行验证其长度是否大于3小于20
我们现在重写BookInfoSerializer序列化器:
from rest_framework import serializers
from book.models import BookInfo
class BookInfoSerializer(serializers.Serializer):
btitle = serializers.CharField(min_length=3,max_length=20)
bpub_date = serializers.DateField()
bread = serializers.IntegerField(read_only=True)
# 序列化附表的主建
# heroinfo_set = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
# 序列化附表的__str__方法的返回值
# heroinfo_set = serializers.StringRelatedField(read_only=True,many=True)
# 使用附表的序列化器
# heroinfo_set = HeroInfoSerializer(many=True)
# 定义单一字段验证的方法
def validate_btitle(self, value):
if value == 'python':
raise serializers.ValidationError('书名不符合规范')
return value
# 定义多字段验证方法
def validate(self, attrs):
if attrs['btitle'] == 'itcast':
raise serializers.ValidationError('itcast不符合规范')
return attrs
# 定义保存方法
def create(self, validated_data):
book = BookInfo.objects.create(btitle=validated_data['btitle'], bpub_date=validated_data['bpub_date'])
return book
# 定义更新方法
def update(self, instance, validated_data):
instance.btitle = validated_data['btitle']
instance.bpub_date = validated_data['bpub_date']
instance.save()
return instance
我们在bookapp的views中书写使用的代码:
class BooksView(View):
# 保存图书
def post(self, request):
data_dict = json.loads(request.body.decode())
# 构造序列化对象,并将要反序列化的数据传递给data构造参数,进而进行验证
serializer = BookInfoSerializer(data=data_dict)
# 验证数据,数据错误时直接返回给前端错误提示
serializer.is_valid(raise_exception=True)
# 保存数据到数据库
serializer.save()
return http.JsonResponse(serializer.data)
class BookView(View):
# 更新单一图书
def put(self, request, pk):
data_dict = json.loads(request.body.decode())
book = BookInfo.objects.get(id = pk)
# 创建序列化对象,并将要反序列化的数据传递给data构造参数,进而进行验证
serializer = BookInfoSerializer(book,data=data_dict)
# 验证数据,is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
serializer.is_valid(raise_exception=True)
# 3、更新数据,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
# 如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。
serializer.save()
return http.JsonResponse(serializer.data)
注意:代码中的注释有对方法的详细说明
附录
模型类数据导入sql:
insert into tb_books(btitle,bpub_date,bread,bcomment,is_delete) values
('射雕英雄传','1980-5-1',12,34,0),
('天龙八部','1986-7-24',36,40,0),
('笑傲江湖','1995-12-24',20,80,0),
('雪山飞狐','1987-11-11',58,24,0);
insert into tb_heros(hname,hgender,hbook_id,hcomment,is_delete) values
('郭靖',1,1,'降龙十八掌',0),
('黄蓉',0,1,'打狗棍法',0),
('黄药师',1,1,'弹指神通',0),
('欧阳锋',1,1,'蛤蟆功',0),
('梅超风',0,1,'九阴白骨爪',0),
('乔峰',1,2,'降龙十八掌',0),
('段誉',1,2,'六脉神剑',0),
('虚竹',1,2,'天山六阳掌',0),
('王语嫣',0,2,'神仙姐姐',0),
('令狐冲',1,3,'独孤九剑',0),
('任盈盈',0,3,'弹琴',0),
('岳不群',1,3,'华山剑法',0),
('东方不败',0,3,'葵花宝典',0),
('胡斐',1,4,'胡家刀法',0),
('苗若兰',0,4,'黄衣',0),
('程灵素',0,4,'医术',0),
('袁紫衣',0,4,'六合拳',0);