drf 数据保存
7.3.2.2 数据保存
通过序列化器来完成数据的更新或者添加,把视图中对于模型中的操作代码移出视图中,放入到序列化器。
前面的验证数据成功后,我们可以使用序列化器来完成数据反序列化的过程.这个过程可以把数据转成模型类对象.
可以通过实现create()和update()两个方法来实现。
from rest_framework import serializers
# 可以把验证函数进行多次使用,提供不用的字段或者不同的序列化器里面使用
def about_django(data):
if "django" in data:
raise serializers.ValidationError("对不起,图书标题不能出现关键字django")
# 返回验证以后的数据
return data
class BookInfoSerializer(serializers.Serializer):
# 这里声明的字段用于进行反序列化器
# 字段名 = serializers.字段类型(验证选项)
title = serializers.CharField(max_length=20,validators=[about_django], label="标题", help_text="标题")
# required=True 当前字段必填
pub_date = serializers.DateField(required=True, label="发布日期", help_text="发布日期")
# max_length 文件的大小
# allow_null=True 允许传递的image数据为None
image = serializers.ImageField(required=False, allow_null=True, max_length=3*1024*1024, label="图书封面", help_text="图书封面")
price = serializers.DecimalField(max_digits=8, decimal_places=2, required=True, label="价格", help_text="价格")
# min_value 数值大小
# default 设置默认值
read = serializers.IntegerField(min_value=0, default=0, label="阅读量", help_text="阅读量")
comment = serializers.IntegerField(min_value=0, default=0, label="评论量", help_text="评论量")
# 关于继承数据库选项
# 自定义验证的代码
# 单个字段的验证,方法名必须: validate_<字段名>(self,data) # data 就是当前字段中客户端提交的数据
# validate_price 会被is_valid调用
def validate_price(self, data):
""""""
if data < 0:
raise serializers.ValidationError("对不起,价格不能低于0元")
# 验证通过以后,必须要返回验证的结果数据,否则序列化器的validated_data无法得到当前字段的结果
return data
# 多个字段的验证,必须方法名叫 "validate"
# data 表示客户端发送过来的所有数据,字典格式
def validate(self, data):
# 判断图书的阅读量不能低于评论量
read = data.get("read")
comment = data.get("comment")
if read < comment:
raise serializers.ValidationError("对不起,阅读量不能低于评论量")
return data
# 数据库操作
def create(self, validated_data): # 这里会在调用时,由序列化器补充验证成功以后的数据进来
"""完成添加操作"""
print(validated_data) # 字典
# 导入模型
from .models import BookInfo
# 添加数据
book = BookInfo.objects.create(
title=validated_data.get("title"),
price=validated_data.get("price"),
pub_date=validated_data.get("pub_date"),
read=validated_data.get("read"),
comment=validated_data.get("comment"),
)
return book
# instance就是要修改的模型,系统会自动从对象初始化时的instance提取过来
# validated_data 就是经过验证以后的客户端提交的数据
def update(self, instance, validated_data):
"""更新操作"""
instance.title = validated_data.get('title')
instance.pub_date = validated_data.get('pub_date')
instance.comment = validated_data.get('comment')
instance.price = validated_data.get('price')
instance.read = validated_data.get('read')
instance.save()
return instance
视图代码:
# Create your views here.
from django.views import View
from django.http.response import HttpResponse
from .serializers import BookInfoSerializer
class BookInfoView(View):
# ...
def get(self,request):
"""保存数据[更新]"""
# 客户端提交数据过来
id = 2
data = { # 模拟客户端发送过来的数据
"title": "东游记",
"pub_date": "1998-10-01",
"price": 19.98,
"read": 330,
"comment": 100,
}
from .models import BookInfo
book = BookInfo.objects.get(pk=id)
# 使用序列化器验证数据[如果是更新操作,需要传入2个参数,分别是instance和data]
serializer = BookInfoSerializer(instance=book,data=data)
serializer.is_valid()
book = serializer.save() # 此时,我们必须在序列化器中预先声明update方法
"""
serailzier对象调用的save方法是什么?怎么做到自动调用update和create?
1. 这里的save不是数据库ORM模型对象的save,是BaseSerializer定义的。
2. save方法中根据实例化serializer时是否传入instance参数来判断执行update还是create的
当传入instance时,则instance.save调用的就是update方法
没有传入instance,则instance.save调用的就是create方法
3. serializer.save使用前提是必须在序列化器中声明create或者update方法,否则报错!!!
"""
print(book)
"""打印结果:
BookInfo object (2)
"""
return HttpResponse("ok")
在序列化器实现了create和update两个方法后,在反序列化数据的时候,就可以通过save()方法返回一个数据对象实例了
book = serializer.save()
如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。
serailzier对象调用的save方法是什么?怎么做到自动调用update和create?
1. 这里的save不是数据库ORM模型对象的save,是BaseSerializer定义的。
2. save方法中根据实例化serializer时是否传入instance参数来判断执行update还是create的
当传入instance时,则instance.save调用的就是update方法
没有传入instance,则instance.save调用的就是create方法
3. serializer.save使用前提是必须在序列化器中声明create或者update方法,否则报错!!!
BaseSerializer中定义的save方法源码:
7.3.2.3 附加参数说明
1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到
# 可以传递任意参数到数据保存方法中
# 例如:request.user 是django中记录当前登录用户的模型对象
serializer.save(owner=request.user)
2)默认序列化器必须传递所有必填字段[required=True],否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新
# Update `BookInfo` with partial data
# partial=True 设置序列化器只是针对客户端提交的字段进行验证,没有提交的字段,即便有验证选项或方法也不进行验证。
serializer = BookInfoSerializer(book, data=data, partial=True)
7.3.3 模型类序列化器
如果我们想要使用序列化器对应的是Django的模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
ModelSerializer与常规的Serializer相同,但提供了:
- 基于模型类自动生成一系列序列化器字段
- 基于模型类自动为Serializer生成validators,比如unique_together
- 包含默认的create()和update()的实现
7.3.3.1 定义
比如我们创建一个BookInfoSerializer
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = '__all__'
- model 指明参照哪个模型类
- fields 指明为模型类的哪些字段生成
我们可以在python manage.py shell中查看自动生成的BookInfoSerializer的具体实现
>>> from booktest.serializers import BookInfoSerializer
>>> serializer = BookInfoSerializer()
>>> serializer
BookInfoSerializer():
id = IntegerField(label='ID', read_only=True)
title = CharField(label='名称', max_length=20)
pub_date = DateField(allow_null=True, label='发布日期', required=False)
read = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
comment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
image = ImageField(allow_null=True, label='图片', max_length=100, required=False)
7.3.3.2 指定字段
- 使用fields来明确字段,
__all__
表名包含所有字段,也可以写明具体哪些字段,如
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date')
- 使用exclude可以明确排除掉哪些字段
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
exclude = ['image',]
- 显示指明字段,如:
class HeroInfoSerializer(serializers.ModelSerializer):
book = BookInfoSerializer()
class Meta:
model = HeroInfo
fields = ('id', 'name', 'sex', 'comment', 'book')
- 指明只读字段
可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'title', 'pub_date', 'read', 'comment')
read_only_fields = ('id', 'read', 'comment')
7.3.3.3 添加额外参数
我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数
class BookInfoSerializer(serializers.ModelSerializer):
"""图书数据序列化器"""
class Meta:
model = BookInfo
fields = ('id', 'title', 'pub_date', 'read', 'comment')
extra_kwargs = {
'read': {'min_value': 0, 'required': True},
'comment': {'min_value': 0, 'required': True},
}
# BookInfoSerializer():
# id = IntegerField(label='ID', read_only=True)
# title = CharField(label='名称', max_length=20)
# pub_date = DateField(allow_null=True, label='发布日期', required=False)
# read = IntegerField(label='阅读量', max_value=2147483647, min_value=0, required=True)
# comment = IntegerField(label='评论量', max_value=2147483647, min_value=0, required=True)
作业
在django项目中实现5个基本的图书信息的API接口,返回json格式数据提供给客户端。
1. 使用基本序列化器 Serializer。
2. 基于模型序列化器来实现5个api接口 ModelSerializer
图书模型:
class BookInfo(models.Model):
"""图书信息"""
title = models.CharField(max_length=20, verbose_name='标题')
pub_date = models.DateField(verbose_name='发布日期')
image = models.ImageField(verbose_name='图书封面')
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name="价格")
read = models.IntegerField(verbose_name='阅读量')
comment = models.IntegerField(verbose_name='评论量')
class Meta:
# db_table = "表名"
db_table = "tb_book_info"
verbose_name = "图书"
verbose_name_plural = verbose_name