文章目录
序列化组件
使用drf的序列化组件:
- 1 新建一个序列化类继承Serializer
- 2 在类中写要序列化的字段
在视图中使用序列化的类:
- 1 实例化序列化的类产生对象,在产生对象的时候,传入需要序列化的对象(queryset)
- 2 对象.data
- 3 return Response(对象.data)
高级用法:
- source:可以指定字段(name publish.name),可以指定方法。
- SerializerMethodField搭配方法使用(get_字段名字)
- read_only:反序列化时,不传
- write_only:序列化时,不显示
序列化
首先创建表models部分:
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
cfn = models.IntegerField(choices=((0,'文学类'),(1,'情感类')),default=0)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField(auto_now_add=True)
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
Serializer不指定表模型
自定义 myserializers.py 文件
class AuthorSerializer(serializers.Serializer):
name = serializers.CharField()
age = serializers.CharField()
class BookSerializer(serializers.Serializer):
# 指定source='name',表示序列化模型表中的name字段,重名命为bookname(name和source='name'指定的name不能重名)
bookname = serializers.CharField(source='name')
# write_only 序列化的时候,该字段不显示
# read_only 反序列化的时候,该字段不传
price = serializers.CharField(write_only=True)
# 如果要跨表取数据,比如取出版社的city,可以通过source来取值:source='publish.city'
publish = serializers.CharField(source='publish.city')
# source不但指定一个字段还可以指定一个函数,get_cfn_display获取类型编号对应的中文注释
classification = serializers.CharField(source='get_cfn_display')
# 序列化出版社的详情,指定SerializerMethodField之后,可以对应一个方法返回什么,publish_detail就是什么内容
publish_detail = serializers.SerializerMethodField()
# 对应的方法固定写法get_字段名
def get_publish_detail(self, obj):
return {'name': obj.publish.name, 'city': obj.publish.city, 'email': obj.publish.email}
# 返回所有作者信息
authors = serializers.SerializerMethodField()
def get_authors(self, obj):
# 利用列表推导式返回
# return [ {'name':author.name,'age':author.age} for author in obj.authors.all()]
# 定义一个AuthorSerializer序列化组建进行序列化
# 这里的obj是是一个book对象所以通过跨表查询obj.authors.all()获取所有的作者,因为有多个作者,这里要指定many=True
authorser = AuthorSerializer(obj.authors.all(), many=True)
return authorser.data
ModelSerializers指定了表模型
自定义 myserializers.py 文件
from rest_framework.exceptions import ValidationError
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
# 获取指定的字段
# fields = ('nid','name')
# 获取所有的字段
fields = ('__all__')
# 深度是1,会自动获取所有的需要跨表的信息,1代表跨一张表,官方建议不要超过10,建议不要超过3
# depth = 1
# 获取所有除了列出的字段,不能跟fields同时使用
# exclude=['name',]
# 重写某个字段在Meta外部,重写某些字段,方式同Serializers
classification = serializers.CharField(source='get_cfn_display')
# 返回所有作者信息
authors = serializers.SerializerMethodField()
对应的 view.py 文件
class Books(APIView):
def get(self,request):
response_dic = {'code':100,'msg':'查询成功!'}
books = models.Book.objects.all()
# 如果序列化多条,many=True(也就是queryset对象,就需要写),如果序列化一条(可以不写),instance是要序列化的对象
booker = BookSerializer(instance=books,many=True)
response_dic['data'] = booker.data
return Response(response_dic)
查询结果
{
"code": 100,
"msg": "查询成功!",
"data": [
{
"nid": 1,
"classification": "情感类",
"authors": [
{
"name": "lin",
"age": "12"
},
{
"name": "wow",
"age": "23"
}
],
"name": "红楼梦",
"cfn": 1,
"price": "12.00",
"publish_date": null,
"publish": {
"nid": 1,
"name": "北京出版社",
"city": "北京",
"email": "[email protected]"
}
}
]
}
反序列化
继承Serializers
使用继承了Serializers序列化类的对象,反序列化,在自己写的序列化类中重写create方法。
自定义 myserializers.py 文件
class BookSerializer(serializers.Serializer):
... ...
def create(self, validated_data):
res = models.Book.objects.create(**validated_data)
return res
对应的 view.py 文件
class Books(APIView):
# 使用继承了Serializers序列化类的对象,反序列化
def post(self,request):
response_dic = {'code': 100, 'msg': '添加成功!'}
# 实例化产生一个序列化类的对象,data是要反序列化的字典
booker = BookSerializer(data=request.data)
if booker.is_valid():
# 清洗通过的数据,通过create方法进行保存
res = booker.create(booker.validated_data)
return Response(response_dic)
继承ModelSerializers
使用继承了ModelSerializers序列化类的对象,反序列化
自定义 myserializers.py 文件与继承了Serializers序列化类的一样,但是要注意定义了depth = 1在保存数据时无法外键的绑定。
对应的 view.py 文件
class Books(APIView):
# 使用继承了ModelSerializers序列化类的对象,反序列化
def post(self, request):
bookser = BookSerializer(data=request.data)
# raise_exception=True调试的时候可以让前端打印信息
if bookser.is_valid(raise_exception=True):
# 清洗通过的数据,通过save方法进行保存
bookser.save()
else:
print(bookser.errors['name'][0])
return Response()
反序列化的校验
局部校验
validate_字段名(self,value):
- 如果校验失败,抛出ValidationError(抛出的异常信息需要去bookser.errors中取)
- 如果校验通过直接return value
class BookSerializer(serializers.Serializer):
... ...
def validate_naem(self,value):
if value.startswith('sb'):
raise ValidationError('不能以sb头')
return value
全局校验
validate(self,attrs):
- attrs所有校验通过的数据,是个字典
- 如果校验失败,抛出ValidationError
- 如果校验通过直接return attrs
class BookSerializer(serializers.Serializer):
... ...
def validate(self, attrs):
if attrs.get('name')==attrs.grt('title'):
raise ValidationError('name和title不能不一致!')
return attrs
源码分析:
- 全局和局部钩子源码部分
is_valid--->
self.run_validation(执行Serializer的run_validation)
self.to_internal_value(data)--->(执行Serializer的run_validation:485行)
全局钩子
ModelSerializer → Serializer → run_validation
通过上面的继承方式最后在Serializer中找的有run_validation()方法
局部钩子
ModelSerializer → Serializer → run_validation_value
通过上面的继承方式最后在Serializer中找的有run_validation_value()方法
- bookser.data
- 序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象
- 序列化对象.data方法 → 调用父类data方法 → 调用对象自己的to_representation(自定义的序列化类无此方法,去父类找)
- Serializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance)
- 再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs当参数传过去,判断是方法就加括号执行,是属性就把值取出来
在序列化的时候,传many=True和many=False,生成的对象并不是一个对象