一、序列化器基本概念
序列化与反序列化
导入serializers:from rest_framework import serializers
- 定义类,继承自Serializer
- 和模型类的字段名字一样
- 和模型类的字段类型一样
- 和模型类的字段选项一样
- read_only=True必须定义,在序列化阶段需要用到
```python
“””模型类”””
from django.db import models
定义书籍模型类
class BookInfo(models.Model): btitle = models.CharField(maxlength=20, verbosename=’名称’) 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=”逻辑删除”) class Meta: db_table = “tb_books” # 指明数据库表名 verbose_name = “图书” # 在admin站点中显示的名称 verbose_name_plural = verbose_name # 显示的复数名称 def __str(self): ‘’’定义每个数据对象的显示信息’’’ return self.btitle
“””序列化器””” from rest_framework import serializers
定义书籍的序列化器
class BookInfoSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True, label=”id”) btitle = serializers.CharField(max_length=20, label=”名称”) bpub_date = serializers.DateTimeField(label=”发布日期”) bread = serializers.IntegerField(default=0, label=”阅读量”) bcomment = serializers.IntegerField(default=0, label=”评论量”) is_delete = serializers.BooleanField(default=False, label=”逻辑删除”)
<a name="ODEdo"></a>
##### (三)、序列化器的序列化使用<br />
- 序列化单个模型类对象
- 从数据库中获取到数据对象
- 根据已经创建的序列化器类实例化序列化器对象,参数是:instance=数据对象
- 序列化器对象.data获取基本的序列化后的结果
```python
from .serializers import BookInfoSerializer
from .models import BookInfo
#序列化操作
#获取书籍对象
book = BookInfo.objects.get(id=5)
#创建序列化器,instance表示需要将哪个对象进行序列化
serializer = BookInfoSerializer(instance=book)
# 转换数据
print(serializer.data)
- 序列化模型类列表对象
- 从数据库中获取到数据对象列表
- 根据已经创建的序列化器类实例化序列化器对象,参数是:instance=数据对象列表, many=True。注意:多个数据对象的时候必须在序列化器中添加many=True,否则会报错
- 序列化器对象.data获取基本的序列化后的结果
from book.models import BookInfo as BookInfoModel
from book.serializers import BookInfoSerializer
# 获取模型类数据对象
books = BookInfoModel.objects.all()
# 实例化序列化器对象
serializer = BookInfoSerializer(instance=books, many=True)
# 打印数据
print(serializer.data)
关联模型的序列化(模型类中有外键子段的模型关联被关联模型类)
序列化器的创建中需要注意的地方:
外键字段使用方式一(关联关联模型的主键):serializers.PrimaryKeyRelatedField(参数)
- 方式一:参数写read_only=True
- 方式二:导入关联字段的模型信息,在参数位置设置:queryset = 模型类.objects.all(),把模型类对象中的所有数据以数据集的形式传入
- 如果不设置参数,程序会报错:AssertionError: Relational field must provide a
queryset
argument, overrideget_queryset
, or set read_only=True
.Note: 外键使用方式二(获取关联模型的str方法返回值):serializers.StringRelatedField(参数),参数的使用和上边的方式一或方式二一样,选择其中一个即可
外键子段使用方式三:直接把关联模型的序列化器作为对内的内容写入,例如:hbook = BookInfoSerializer()。hbook是外键
- 创建模型对象和序列化器实例对象,打印结果:
- 关联主键的打印:字段信息是关联模型的主键/id数据
- 关联str方法的打印:字段信息是关联模型类中定义好的str方法的返回值信息
# 定义英雄的序列化器
class HeroInfoSerializer(serializers.Serializer):
GENDER_CHOICE = (
(0, 'female'),
(1, 'male')
)
id = serializers.IntegerField(read_only=True, label="id")
hname = serializers.CharField(max_length=20, label="名称")
hgender = serializers.ChoiceField(choices=GENDER_CHOICE, label="性别", required=False)
# allow_null=True允许为空值
hcomment = serializers.CharField(max_length=200, label="描述信息", required=False, allow_null=True)
is_delete = serializers.BooleanField(default=False, label="逻辑删除")
# 方式一:关联外键主键
# hbook = serializers.PrimaryKeyRelatedField(read_only=True)
# 方式二:关联外键子段的字符串信息__str__
# hbook = serializers.StringRelatedField(read_only=True)
# 方式三:关联BookInfoSerializer序列化器
hbook = BookInfoSerializer()
- 关联模型的序列化(被关联模型关联有外键子段的模型类)
- 被关联模型类中没有设置外键
- 如何查询被关联模型信息的时候,关联有外键子段的模型类,把对应的关联信息一并取出?
- 方式一(关联主键):有外键子段的模型类名_set = serializers.ForeignKeyRelatedField(read_only=True, many=True)
- 方式二(关联str方法):有外键子段的模型类名_set = serializers.StringRelatedField(read_only=True, many=True)
Note:
- “有外键子段的模型类名”必须全部小写,不能采用驼峰命名,并且后边必须加上_set,单下划线,不是双下划线
- many=True:当出现要查询的结果不只一条的时候必须加上many=True,这在整个drf的序列化器中都是通用的,如果没有many=True程序就会报错
from rest_framework import serializers
from book.models import BookInfo as BookInfoModel
# 定义书籍的序列化器
class BookInfoSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True, label="id")
btitle = serializers.CharField(max_length=20, label="名称")
bpub_date = serializers.DateField(label="发布日期")
bread = serializers.IntegerField(default=0, label="阅读量")
bcomment = serializers.IntegerField(default=0, label="评论量")
is_delete = serializers.BooleanField(default=False, label="逻辑删除")
# 关联英雄类的主键
# heroinfo_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
# 关联英雄模型__str__方法
heroinfo_set = serializers.StringRelatedField(read_only=True, many=True)
# 定义英雄的序列化器
class HeroInfoSerializer(serializers.Serializer):
GENDER_CHOICE = (
(0, 'female'),
(1, 'male')
)
id = serializers.IntegerField(read_only=True, label="id")
hname = serializers.CharField(max_length=20, label="名称")
hgender = serializers.ChoiceField(choices=GENDER_CHOICE, label="性别", required=False)
hcomment = serializers.CharField(max_length=200, label="描述信息", required=False, allow_null=True)
is_delete = serializers.BooleanField(default=False, label="逻辑删除")
# 关联外键主键
# hbook = serializers.PrimaryKeyRelatedField(read_only=True)
# 关联外键子段的字符串信息__str__
# hbook = serializers.StringRelatedField(read_only=True)
#
# 关联BookInfoSerializer
hbook = BookInfoSerializer()
(四)、序列化器的反序列化使用
校验:
字段类型校验
- IntegerField:整数
- CharField:字符串
- DateField:日期校验
- BooleanField:布尔类型
- 更多见文档……
# 反序列化时使用data,序列化时使用instace
serializer = BookInfoSerializer(data=book_dist)
# raise_exception=True:如果校验不通过,则抛出异常信息
serializer.is_valid(raise_exception=True)
print(serializer.data)
字段选项校验
- max_length:最大长度
- min_length:最小长度
- required:false/true,默认为true,如果为false,可以不用传递该字段
- default: 默认值,出现默认值的时候,该字段也可以不传递
- Read_only:只读属性,默认为false,当为true的时候,反序列化的时候也可以不用传递该字段
单字段校验(方法)
- 校验方法名:validate_字段名,必须是这个格式的
- 参数:self和value,value是这个字段传递过来的值
- 校验方法必须写在模型类里
- 校验不通过抛出异常:raise serializers.ValidationError(“错误信息提示内容”)
def validate_btitle(self, value):
if("西游" not in value):
raise serializers.ValidationError("标题必须包含'西游'两个字")
return value
多字段校验(方法)
- 应用场景:客户端传递过来的内容需要和数据库、缓存中的内容进行比对的字段必须用到多字段校验,例如:短信验证码、图片验证码等
- 方法名:必须是validate
- 参数:self和value,value可以是任意的名字,表示的是从客户端传递过来的所有数据
- 校验方法必须写在模型类里
- 校验不通过抛出异常:raise serializers.ValidationError(“错误信息提示内容”)
# 多字段校验
def validate(self, value):
# value是客户端传递过来的所有的数据
# 获取阅读量和评论量
bread = value['bread']
bcomment = value['bcomment']
if(bread < bcomment):
raise serializers.ValidationError("阅读量不能小于评论量")
return value
注意:无论是单字段还是多字段校验,校验成功的返回值必须是形参value,否则会报错
自定义校验(方法)
- 方法名:随意写,不受限制,但最好和校验的字段名相关
- value是校验字段传递过来的数据值
- 校验方法必须写在模型类的前边,否则程序会报找不到自定义方法的错误
- 在需要校验的字段的参数重添加validators=[校验方法],需要注意的是,这是一个列表格式的,校验的方法可以有很多,并且校验的方法名直接写入,不能加引号
- 如果校验失败报异常,如果校验成功,必须返回value参数
```python
自定义校验
def check_bpub_date(value): if value.year <= 2018: raise serializers.ValidationError(“书籍的年份必须大于等于2018”) return value
校验字段
bpub_date = serializers.DateField(label=”发布日期”, validators=[check_bpub_date])
- 入库
- 情况一:创建新的对象(create)
- 当使用序列化器.save()方法入库时,必须先在序列化器中重写create()方法,否则会报错:`create()` must be implemented
- 重写create方法
- 方法名:create()
- 参数:self和validated_data,validated_data必须是这个名字,表示已经校验过的数据
- 方法内容:使用模型类中的create()方法来实现,参数是**validated_data
- 返回值为:模型类对象
```python
"""序列化器中重写create()方法"""
# 实现create方法
def create(self, validated_data):
# 创建book对象,设置属性,入库
book = BookInfoModel.objects.create(**validated_data)
# 返回
return book
"""视图中"""
# save()方法会去调用create()方法
serializer.save()
- 情况二:更新已有的对象(update)
- 实例化序列化器,这里需要注意的是:参数必须是两个:instance=模型类对象、data=客户端传递的数据,这一点必须注意。序列户阶段,参数是instance,反序列化阶段的创建对象必须是data,但是反序列化阶段的更新必须是两个参数都得写上
- 如果直接调用serializer.save()方法,程序会报
update()
must be implemented错误,所以,需要在模型类中重写update()方法 - 重新update()方法
- 参数:self,instance和validated_data
- 方法内更新数据:instance.字段名 = validated_data[‘字段名’]
- 执行更新操作:instance.save()
- 返回值:return instance
需要注意的是:因为是更新操作,更新需要知道是哪一条数据,所以instance代表的就是需要更新的数据对象
"""序列化器"""
# 重写update()方法
def update(self, instance, validated_data):
# 更新数据
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
"""视图类"""
# 更新某一条数据信息
def put(self, request, pk):
# 获取数据
book_dict = json.loads(request.body.decode())
# 实例化对象
book = BookInfo.objects.get(id=pk)
# 实例化序列化器
serializer = BookInfoSerializer(instance=book, data=book_dict)
serializer.is_valid(raise_exception=True)
# save()方法调用的是序列化器中的update()方法
serializer.save()
return JsonResponse(serializer.data)