drf—— 序列化组件
----->序列化器-Serializer
一、序列化组件介绍
#作用:
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
-Book模型--序列化器--->字典--通过drf:Response--》json格式字符串--->传给前端
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
json格式数据---通过drf:Request-->字典---序列化器---》Book模型
3. 反序列化,完成数据校验功能
二、序列化组件简单使用
# 序列化的使用
-写一个序列化类继承serializers.Serializer
-在类中写要序列化的字段
-在视图类中,实例化得到一个序列化类的对象,把要序列化的数据传入
ser=BookSerializer(instance=res,many=True)
-得到字典
ser.data就是序列化后的字典
三、序列化组件使用代码实现
'''5个接口 1. 查询所有 Book--》get 2. 查询单个 BookDetali--》get 3. 新增一个 Book--》post 4. 删除一个 BookDetali--》delete 5. 修改一个 BookDetali--》put '''
1.查询所有
url:127.0.0.1.8000/books/ # 注意最后面的 /一定要写
models.py # 建立好模型,进行数据迁移,在数据库中手动添加至少2条数据
from django.db import models
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32,null=True) #测试read_only
price = models.DecimalField(max_digits=5, decimal_places=2)
publish = models.CharField(max_length=32)
urls.py #配置好路由
path('books/', views.Book.as_view()),
views.py #写视图类
from rest_framework.views import APIView
from rest_framework.response import Response
from app01 import models
from app01.serializer import BookSerializer
class Book(APIView):
def get(self, request, *args, **kwargs):
res = models.Book.objects.all()
# 借助序列化器
# 如果是多条,就是many=True
# 如果是单个对象,就不写
ser = BookSerializer(instance=res, many=True)
print(type(ser)) # rest_framework.serializers.ListSerializer
# 通过序列化器得到的字典
# ser.data
print(ser.data)
return Response(ser.data)
serializer.py #在app中创建存放序列化器的 类的文件 serializer.py 并写BookSerializer类
# 序列化器类(序列化Book表)
# from rest_framework.serializers import Serializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models
class BookSerializer(serializers.Serializer):
# 要序列化哪个字段
id = serializers.IntegerField(required=False)
# id=serializers.CharField()
title = serializers.CharField(max_length=32,min_length=2,read_only=True)
price = serializers.DecimalField(max_digits=5, decimal_places=2)
# 序列化的时候看不到,因为write_only=Truepublish = serializers.CharField(max_length=32,write_only=True)
2.查询单个
url:127.0.0.1.8000/books/1 #后面的数字代表查询id为几的数据
urls.py中加
re_path('^books/(?P<id>\d+)', views.BookDetail.as_view()),
views.py中加
class BookDetail(APIView):
def get(self, request, id):
res = models.Book.objects.all().filter(id=id).first()
# 单个,去掉many=True
# 加many=True和不加,ser不是同一个对象,查单个是BookSerializer对象,查多个是ListSerializer对象,这是由源码中元类决定的
ser = BookSerializer(instance=res)
print(type(ser)) # 打印出 app01.serializer.BookSerializer
return Response(ser.data)
3.新增一个 ---这里涉及到保存!!!
ps:新增必须写create方法
urls.py 不变
views.py
class Book(APIView):
def get(self, request, *args, **kwargs):
...
def post(self, request):
# post提交的数据都在request.data 是个字典
print(request.data)
ser = BookSerializer(data=request.data)
if ser.is_valid(): # 校验数据是否合法
ser.save() # 保存到数据库中
return Response(ser.data)
else:
# 没有校验通过的错误信息
return Response(ser.errors)
serializer.py
# 如果序列化类继承的是Serializer,必须重写create方法
class BookSerializer(serializers.Serializer):
...
def create(self, validated_data):
# 为什么要重写create?为了跟views.py里面的Book表建立关系
res=models.Book.objects.create(**validated_data)
print(res)
return res
4.修改
ps:必须写update方法
urls.py不变
views.py
class BookDetail(APIView):
def get(self, request, id):
...
def put(self, request, id):
# 通过id取到对象
res = {'code': 100, 'msg': ''}
try:
book = models.Book.objects.get(id=id)
ser = BookSerializer(instance=book, data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
res['msg'] = '修改成功'
res['result'] = ser.data
except Exception as e:
res['code'] = 101
res['msg'] = str(e)
return Response(res)
serializer.py
class BookSerializer(serializers.Serializer):
...
def update(self, book, validated_data):
book.title=validated_data.get('title')
book.price=validated_data.get('price')
book.publish=validated_data.get('publish')
book.save()
return book
5.删除
views.py
class BookDetail(APIView):
...
def delete(self,request,id):
response = {'code': 100, 'msg': '删除成功'}
models.Book.objects.filter(id=id).delete()
return Response(response)
四、序列化类字段类型和字段参数
# 常用字段类型
-IntegerField
-CharField
-DecimalField
-DateTimeField
-。。。跟models中大差不差
# 常用字段参数
-选项参数
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 包含错误编号与错误信息的字典
---------------------序列化器-------------------------
五、序列化器的(反序列化之)保存功能
同三中3.增加一个 里面的保存
六、序列化器的(反序列化之)字段校验功能
validators校验,局部钩子,全局钩子
ps:validators 列表里面可以传多个值进行校验
# 三种方式
-字段自己的校验规则(max_length...)
-validators的校验
publish = serializers.CharField(max_length=32,validators=[check,])
def check(data):
if len(data)>10:
raise ValidationError('最长不能超过10')
else:
return data
-局部和全局钩子
# 局部钩子,validate_字段名,需要带一个data,data就是该字段的数据
def validate_title(self, data):
if data.startswith('sb'):
raise ValidationError('不能以sb开头')
else:
return data
# 全局钩子
def validate(self, attrs):
title=attrs.get('title')
publish=attrs.get('publish')
if title==publish:
raise ValidationError('书名不能跟出版社同名')
else:
return attrs
七、序列化类常用字段参数之read_only和write_only
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
class BookSerializer(serializers.Serializer):
# 要序列化哪个字段
id = serializers.IntegerField(required=False)
# id=serializers.CharField()
title = serializers.CharField(max_length=32,min_length=2,read_only=True)
price = serializers.DecimalField(max_digits=5, decimal_places=2)
# 序列化的时候看不到
publish = serializers.CharField(max_length=32,validators=[check,],write_only=True)
八、(反序列化之)高级用法之source
总结:
1用法一: 修改返回到前端的字段名
# 若source=title 那么字段名就不能再叫title,这里叫了name
name = serializers.CharField(max_length=32,min_length=2,source='title')
2用法二: 如果表模型中有方法
class Book(models.Model):
...
def test(self):
# python是强类型语言,不支持字符串和数字直接相加
return self.title+str(self.price)
# 执行表模型中的test方法,并且把返回值赋值给xxx
xxx=serializers.CharField(source='test')
3用法三: source支持跨表操作
addr=serializers.CharField(source='publish.addr')
# 可以去看源码,内部如何实现的
代码:
urls.py
models.py
from django.db import models
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32,null=True) #测试read_only
price = models.DecimalField(max_digits=5, decimal_places=2)
# publish = models.CharField(max_length=32)
#修改后
publish = models.ForeignKey(to='Publish',null=True,on_delete=models.CASCADE)
#这是在测试source第一种方法时加的
def test(self):
# python是强类型语言,不支持字符串和数字直接相加
return self.title+str(self.price)
#新建一张publish表
class Publish(models.Model):
name=models.CharField(max_length=32)
addr=models.CharField(max_length=32)
#重写__str__
def __str__(self):
return self.name
views.py
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
#方法一
name = serializers.CharField(max_length=32,min_length=2,source='title')
price = serializers.DecimalField(max_digits=5, decimal_places=2)
#方法三,要直接显示出publish的名字 ,或 在models.py中重写__str__
publish = serializers.CharField(max_length=32,source='publish.name')
#方法二
xxx=serializers.CharField(source='test')
#方法三:跨表
publish_addr=serializers.CharField(source='publish.addr')
九、模型类序列化器
1 原来用的Serilizer跟表模型没有直接联系, 模型类序列化器ModelSerilizer,跟表模型有对应关系
2 使用
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model=表模型 # 跟哪个表模型建立关系
fields=[字段,字段] # 序列化的字段,反序列化的字段
fields='__all__' # 所有字段都序列化,反序列化
exclude=[字段,字段] # 排除哪些字段(不能跟fields同时使用)
read_only_fields=['price','publish'] # 序列化显示的字段
write_only_fields=['title'] # 反序列化需要传入的字段
extra_kwargs ={'title':{'max_length':32,'write_only':True}}
depth=1 # 了解,跨表1查询,最多建议写3
# 重写某些字段
publish = serializers.CharField(max_length=32,source='publish.name')
# 局部钩子,全局钩子,跟原来完全一样
3 新增,修改
-统统不用重写create和update方法了,在ModelSerializer中重写了create和update
十、(反序列化之)高级用法之SerializerMethodField
#方式一:Serializer
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False)
name = serializers.CharField(max_length=32,min_length=2,source='title')
price = serializers.DecimalField(max_digits=5, decimal_places=2)
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
dic={'name':obj.publish.name,'addr':obj.publish.addr}
return dic
#方式二:ModelSerializer
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__'
publish = serializers.SerializerMethodField()
def get_publish(self,obj):
dic={'name':obj.publish.name,'addr':obj.publish.addr}
return dic
# 方式三:使用序列化类的嵌套
class PublishSerializer(serializers.ModelSerializer):
class Meta:
model = models.Publish
# fields = '__all__'
fields = ['name','addr']
class BookModelSerializer(serializers.ModelSerializer):
publish = PublishSerializer()
class Meta:
model = models.Book
fields = '__all__'
十一、序列化组件源码分析
#序列化组件,先调用__new__方法,如果many=True,生成ListSerializer对象,如果为False,生成Serializer对象 #序列化对象.data方法--调用父类data方法---调用对象自己的to_representation(自定义的序列化类无此方法,去父类找) #Aerializer类里有to_representation方法,for循环执行attribute = field.get_attribute(instance) #再去Field类里去找get_attribute方法,self.source_attrs就是被切分的source,然后执行get_attribute方法,source_attrs #当参数传过去,判断是方法就加括号执行,是属性就把值取出来
赞 (0)
