摘要.
使用 Django 前后端分离开发的情况下,我们经常需要把处理后的数据按照一定的格式(比如说 json)返回,或者把前端传过来的数据进行处理才能进行数据库的 CURD。而 DRF(Django REST Framework)就可以帮忙我解决这个问题,即序列化和反序列化
# 1. 安装 DRF
使用 pip 安装
pip install djangorestframework
配置应用
INSTALLED_APPS = [
...
'rest_framework',
]
# 2. 定义 Serializer
我们新建一个 py 文件专门写序列化类继承 serializers.Serializer,写的字段和约束要在模型类范围之内
models.py
from django.db import models
class BookInfo(models.Model):
btitle = models.CharField(max_length=20, verbose_name='名称')
bpub_date = models.DateField(verbose_name='发布日期', null=True)
bread = models.IntegerField(default=0, verbose_name='阅读量')
bcomment = models.IntegerField(default=0, verbose_name='评论量')
image = models.ImageField(upload_to='booktest', verbose_name='图片', null=True)
serializers.py
from rest_framework import serializers
class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
id = serializers.IntegerField(label='ID', read_only=True)
btitle = serializers.CharField(label='名称', max_length=20)
bpub_date = serializers.DateField(label='发布日期', required=False)
bread = serializers.IntegerField(label='阅读量', required=False)
bcomment = serializers.IntegerField(label='评论量', required=False)
image = serializers.ImageField(label='图片', required=False)
说明:Serializer 的字段类型几乎与 Models 的一样,记不起来时直接查看 serializers 类即可
选项参数 | 说明 |
---|---|
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 | 包含错误编号与错误信息的字典 |
label | 用于 HTML 展示 API 页面时,显示的字段名称 |
help_text | 用于 HTML 展示 API 页面时,显示的字段帮助提示信息 |
# 3. 创建 Serializer 对象
Serializer(instance=None, data=empty, **kwarg)
说明:
- 序列化时,instance 传入模型类对象
- 反序列化时,data 传入被反序列化的数据
# 4. 简单序列化
序列化单个对象
from booktest.models import BookInfo
from booktest.serializers import BookInfoSerializer
book = BookInfo.objects.get(id=2)
serializer = BookInfoSerializer(book)
serializer.data
序列化查询集
books = BookInfo.objects.all()
serializer = BookInfoSerializer(books, many=True)
serializer.data
# 5. 关联嵌套序列化(外键)
如果存在外键,在序列化的时候可能是序列化主表或从表两大方向
models.py
class BookInfo(models.Model):
...
def __str__(self):
return self.btitle
class HeroInfo(models.Model):
...
hbook = models.ForeignKey(BookInfo, related_name='heros',on_delete=models.CASCADE, verbose_name='图书')
def __str__(self):
return self.hname
# 5.1 序列化主表
serializers.py
class HeroInfoSerializer(serializers.Serializer):
id = serializers.IntegerField()
hname = serializers.CharField()
hgender = serializers.IntegerField()
hcomment = serializers.CharField()
is_delete = serializers.BooleanField()
class BookInfoSerializer(serializers.Serializer):
id = serializers.IntegerField()
btitle = serializers.CharField()
bpub_date = serializers.DateField()
bread = serializers.IntegerField()
bcomment = serializers.IntegerField()
is_delete = serializers.BooleanField()
image = serializers.ImageField()
序列化主表BookInfo的时候,它的属性heros是关联的从表的多个对象
关联对象序列化方案一:序列化成关联对象的主键
heros = serializers.PrimaryKeyRelatedField(
queryset=HeroInfo.objects.all(),
many=True
)
关联对象序列化方案二:序列化成关联对象的__str__方法返回的结果
heros = serializers.StringRelatedField(many=True)
关联对象序列化方案三:自定义关联对象序列化
heros = HeroInfoSerializer(many=True)
# 5.1 序列化从表
serializers.py
class BookInfoSerializer(serializers.Serializer):
btitle = serializers.CharField()
bpub_date = serializers.DateField()
bread = serializers.IntegerField()
bcomment = serializers.IntegerField()
is_delete = serializers.BooleanField()
image = serializers.ImageField()
class HeroInfoSerializer(serializers.Serializer):
id = serializers.IntegerField()
hname = serializers.CharField()
hgender = serializers.IntegerField()
hcomment = serializers.CharField()
is_delete = serializers.BooleanField()
代表当前英雄对象(从),关联的书本(主)单一对象
hbook = serializers.PrimaryKeyRelatedField(
queryset=BookInfo.objects.all()
)
hbook = serializers.StringRelatedField()
hbook = BookInfoSerializer()
三种形式说明
(1)、PrimaryKeyRelatedField(queryset,many)
(2)、StringRelatedField()
(3)、自定义序列化器
# 6. 反序列化
# 6.1 操作步骤
(1)获取有效数据
book_info = {"btitle": "围城", "bpub_date": "1999-9-9"}
(2)实例化序列器对象
bs = BookInfoSerializer(data=book_info, partial=True)
data 是要被校验的数据,partial 为 True 是部分校验,有什么就校验什么
(3)启动校验流程
bs.is_valid()
当调用 is_valid() 方法即开始校验,包括约束条件校验、类型校验、validators 校验、validate_<字段名> 校验、validate 校验,若全部校验通过返回 True,否则返回 False
(4)获得最终结果
若校验成功,查看有效数据
bs.validated_data
若校验失败,查看失败信息
bs.errors
(3)自定义校验之 1:validators
serializers.py
def check_btitle(value):
if "django" not in value:
raise serializers.ValidationError("这不是一本关于django的书")
class BookInfoSerializer(serializers.Serializer):
btitle = serializers.CharField(其他校验,validators=[check_btitle]
...
(3)自定义校验之 2:validate_<字段名>
serializers.py
class BookInfoSerializer(serializers.Serializer):
...
btitle = serializers.CharField(label='名称',max_length=20,)
def validate_btitle(self, value):
if "django" not in value:
raise serializers.ValidationError("这不是一本关于django的书")
return value
(3)自定义校验之 3:validate
serializers.py
class BookInfoSerializer(serializers.Serializer):
...
btitle = serializers.CharField(label='名称',max_length=20,)
def validate(self, attrs):
btitle = attrs.get('btitle')
if 'django' not in btitle:
raise serializers.ValidationError('这不是一本关于django的书')
return attrs
第 3 种校验方式最常用,因为它可以对所以字段进行自定义校验
# 6.2 新建和更新操作
前端传过来的数据要写进数据库,可能是新建一条新的数据,也可能只是更新部分字段,在调用 save() 方法的时候会执行新建或更新操作
实例化序列号器对象的时候,如果只传入 data 不传 instance 即为新建,若两者都传即为更新数据,
新建和更新的本质是调用我们在序列化器重写的 create() 和 update() 这两个方法
serializers.py
class BookInfoSerializer(serializers.Serializer):
btitle = serializers.CharField(label='名称',max_length=20)
...
def create(self, validated_data):
instance = BookInfo.objects.create(**validated_data)
return instance
def update(self, instance, validated_data):
for field,value in validated_data.items():
setattr(instance, field, value)
instance.save()
return instance
举例
book_info = {"btitle": "django精通"....}
book = BookInfo.objects.get(pk=6)
bs = BookInfoSerializer(instance=book, data=book_info)
bs.is_valid()
bs.save()
# 7. 补充
# 7.1 PrimaryKeyRelatedField 作用于反序列化
- PrimaryKeyRelatedField 作用于序列化的时候,把关联对象序列化成主键
- PrimaryKeyRelatedField 作用与反序列化的时候,把主键反序列化成关联的对象
# 7.2 全更新与部分更新
- 全更新就是全部字段,必传必校验(默认)
- 部分更新就是部分字段,必要字段可传可不传,传就会被校验(如更新部分字段操作)
Serializer(instance=模型类对象,data=参数)
Serializer(instance=模型类对象,data=参数,partial=True)
# 7.3 save 方法传递关键字参数
一般情况下是在实例化序列化器的时候就用 data 参数传输待校验的数据,但是后续可能需要指定其他字段,这时候可以在调用 save() 方法的时候传入其他参数
https://blog.csdn.net/qq_39147299/article/details/108691882 https://blog.csdn.net/qq_39147299/article/details/108691882