序列化器
序列化组件
1.简单介绍
- 序列化:序列器会把模型转成字典,经过response以后变成json字符串
- 反序列化:把客户端传过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
2.使用
- 建立orm,创建一个py文件,写一个序列化器,继承Serializer
- 在类中书写序列化的字段
- 在视图中导入实例化得到的序列化类的对象,把要序列化的对象传入进去
- 序列化类的对象.data 这里是一个字典
- 把字典返回,如果不适应rest_framework提供的Response,l可以使用JsonResponse
# ser.py
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
price = serializers.CharField() #创建你要序列化的字段
# views.py
class BookAPIView(APIView):
def get(self, request, pk):
book = models.Book.objects.filter(id=pk).first()
book_ser = BookSerializer(book) # 要序列化谁就把谁传过来, # 调用类的__init__
return Response(book_ser.data) # 序列化对象.data就是序列化后的字典
#url
re_path('books/(?P<pk>\d+)', views.BookAPIView.as_view()),
补充:还有很多的字段类型
CharField,IntegerField,DateField
3. 单个数据的修改和展示
上面是简单的使用,这个是对某一个数据的更新。
-
在类中写要序列化的字段,像序列化哪个就写哪个,里面还可以添加一些参数
max_length 最大长度 min_lenght 最小长度 allow_blank 是否允许为空 trim_whitespace 是否截断空白字符 max_value 最小值 min_value 最大值
-
在视图中使用,实例化得到序列化的对象,把要修改的对象传入,修改的数据传入
-
校验数据,通过保存
-
如果字段的校验规则不够我们可以自己写钩子
# ser.py
class BookSerializer(serializers.Serializer):
title = serializers.CharField(max_length=6,min_length=2)
price = serializers.CharField()
author = serializers.CharField(max_length=6,min_length=2)
publish = serializers.CharField(max_length=6,min_length=2)
# view.py
class BookAPIView(APIView):
def put(self,request,pk):
response_msg = {'state':100,'msg':'成功'}
book = models.Book.objects.filter(id=pk).first()
# 更新或修改某个字段要传两个参数
book_obj = BookSerializer(instance=book,data=request.data) # 传两个参数对象和数据
# 验证数据
if book_obj.is_valid():
# 这里不能直接用save要重写
book_obj.save()
response_msg['data']=book_obj.data
else:
response_msg['state']=101
response_msg['msg'] = '数据校验失败'
response_msg['data']=book_obj.errors
return Response(response_msg)
3.1 ser.py中的局部钩子和全局钩子
from rest_framework.exceptions import ValidationError
# 局部钩子
def validate_author(self, data):
if '啊' in data:
raise ValidationError('作者名不能有啊')
else:
return data
def validate(self, validate_data):
author = validate_data.get('author')
publish = validate_data.get('publish')
if author==publish:
raise ValidationError('作者名字不能和出版社一样哦')
else:
return validate_data
3.2 重写update方法
- 我们在修改数据的时候用save(),不能直接保存,需要我们重新在ser.py中重写update方法
def update(self, instance, validated_data):
instance.name = validated_data.get('title')
instance.price = validated_data.get('price')
instance.author = validated_data.get('author')
instance.publish = validated_data.get('publish')
instance.save()
return instance
-
instance 是book这个对象
-
validated_data是校验过的数据
-
instance.save()相当于book.save()
{
"state": 101,
"msg": "数据校验失败",
"data": {
"non_field_errors": [
"作者名字不能和出版社一样哦"
]
}
}
drf返回错误信息的标准写法,要有返回的错误信息
3.3 read_only 和write_only
-
read_only 表明该字段只用于序列化输出,默认是False,设置成True,在postman里面可以看到该字段,修改的时候不需要传该字段
# get方法序列化的时候输出 { "title": "西游记", "price": "22", "author": "你得到", "publish": "西方出版社" } # put方法反序列化的时候输入 { "title": "西游记", "price": "22", "publish": "北方出版社" }
-
write_only 表明该字段只用于反序列化输入的时候,默认是False,设置成True,在postman里面看不到该字段,修改需要修改
展示时 { "title": "西游记", "price": "22", "publish": "西方出版社" } 修改时 { "title": "西游记", "price": "22", "publish": "西方出版社", "author":"南门吹雪" }
4 查询所有和新增数据
4.1 查看所有
class BooksAPIView(APIView):
def get(self, request):
response_msg = {'state': 100, 'msg': '成功'}
books = models.Book.objects.all()
books_ser = BookSerializer(books, many=True)#这里我们要查所有的字段要加参数many
response_msg['data'] = books_ser.data
return Response(response_msg)
- 这里为什么要加参数呢
4.2 many的源码
def __new__(cls, *args, **kwargs):
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
return super().__new__(cls, *args, **kwargs)
这里对象没有生成之前调用__new__
方法,生成空对象,触发__init__
,__new__
控制对象的生成
- 先去BookSerializer去找
_new__
方法没有到父类,找到__new__
方法 - 从kwrags取出参数pop,many默认是False,因为我们设置many是True执行下面的return,正常的实例化,many_init
@classmethod
def many_init(cls, *args, **kwargs):
list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
return list_serializer_class(*args, **list_kwargs)
我们看到这个他是一个list,每一个都是BookModelSerializer对象
4.3 新增数据
def post(self,request):
response_msg = {'state': 100, 'msg': '成功'}
book_ser = BookSerializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
def create(self, validated_data):
isinstance = models.Book.objects.create(**validated_data)
return isinstance
这里也遇到一个问题要重新写create方法才能保存
4.4 create方法的重写
def create(self, validated_data):
isinstance = models.Book.objects.create(**validated_data)
return isinstance
4.5 删除数据
def delete(self, request, pk):
models.Book.objects.filter(pk=pk).delete()
response_msg = {'state': 100, 'msg': '成功'}
return Response(response_msg)
5. 模型化类器
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = '__all__' # 序列化所有
exclude = ('title') # 排除title序列化其他字段,不能和fileds连用
extra_kwargs = { # 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
'price': {'write_only': True},
}
- 在3.2之后的模型类中write_only_fields弃用了
其他该写上面参数写什么参数,也可以不用重新写create和update方法
6. 自己封装Response
7. Serializer高级用法
SerializerMethodField()的使用的使用
{
"title": "西游记",
"price": "12",
"pub_date": "2020-07-28",
"publish": "Publish object",
"authors": "app01.Author.None"
}
当我们跨表查询的时候,发现出版社和作者是一个对象,我们要在后端把他取出来实例化展示
authors = serializers.SerializerMethodField()
def get_authors(self,instance):
authors = instance.authors.all()
authors_list = []
for author in authors:
authors_list.append({'name':author.name,'age':author.age})
return authors_list
- 先定义一个列表,取出所有的作者,for循环把所有的作者用字典的形式添加到里面
source的使用:
-
1 可以改字段名字
xxx=serializers.CharField(source='title')
-
2 可以.跨表
publish=serializers.CharField(source='publish.email')
-
3 可以执行方法
pub_date=serializers.CharField(source='test')
test是Book表模型中的方法
它里面默认的book.authors
等