一、序列化器基本概念
序列化与反序列化
导入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获取基本的序列化后的结果```pythonfrom .serializers import BookInfoSerializerfrom .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 BookInfoModelfrom 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
querysetargument, 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 serializersfrom 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)## 关联BookInfoSerializerhbook = BookInfoSerializer()
(四)、序列化器的反序列化使用
校验:
字段类型校验
- IntegerField:整数
- CharField:字符串
- DateField:日期校验
- BooleanField:布尔类型
- 更多见文档……
# 反序列化时使用data,序列化时使用instaceserializer = 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)
