前言
- 本篇来学习Serializer序列化器知识
序列化器作用
- 进行数据的校验
- 对数据对象进行转换
定义Serializer
定义方法
- 模型
# models.py from django.db import models # Create your models here. # 准备书籍列表信息的模型类 class BookInfo(models.Model): # 创建字段,字段类型 name = models.CharField(max_length=20, verbose_name='名称') # verbose_name admin管理后台使用 pub_date = models.DateField(verbose_name='发布日期', null=True) readcount = models.IntegerField(default=0, verbose_name='阅读量') commentcount = models.IntegerField(default=0, verbose_name='评论量') is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') class Meta: db_table = 'bookinfo' # 指明数据库表名 verbose_name = '图书' # 在admin站点中显示的名称 def __str__(self): """定义每个数据对象的显示信息""" return self.name
- 序列化器
# -*- coding: utf-8 -*- # @Time : 2022/9/24 # @Author : 大海 # serializers.py from rest_framework import serializers from book.models import BookInfo class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" name = serializers.CharField(max_length=20, label='名称') # label DRF接口页面展示使用 pub_date = serializers.DateField(label='发布日期', required=True) readcount = serializers.IntegerField(required=False, label='阅读量') commentcount = serializers.IntegerField(required=False, label='评论量') is_delete = serializers.BooleanField(required=False, label='逻辑删除')
字段与选项
- 常用字段类型
- 选项参数
参数名称 | 作用 |
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页面时,显示的字段帮助提示信息 |
创建Serializer对象
Serializer的构造方法为:
Serializer(instance=None, data=empty, **kwarg)
说明:
1)用于序列化时,将模型类对象传入instance参数
2)用于反序列化时,将要被反序列化的数据传入data参数
3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据,如
serializer = AccountSerializer(account, context={‘request’: request})
通过context参数附加的数据,可以通过Serializer对象的context属性获取。
序列化使用
基本使用
- 进入Django shell模式
python manage.py shell
- 查询一个图书对象
from book.models import BookInfo book = BookInfo.objects.get(id=1)
- 构造序列化器
from book.serializers import BookInfoSerializer serializer = BookInfoSerializer(book)
- 获取序列化数据
serializer.data
- 如果要被序列化的是包含多条数据的查询集QuerySet,可以通过添加many=True参数补充说明
books = BookInfo.objects.all() serializer = BookInfoSerializer(books,many=True) serializer.data
增加额外字段
# serializers.py from rest_framework import serializers class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" name = serializers.CharField(max_length=20, label='名称') # label DRF接口页面展示使用 pub_date = serializers.DateField(label='发布日期', required=True) readcount = serializers.IntegerField(required=False, label='阅读量') commentcount = serializers.IntegerField(required=False, label='评论量') is_delete = serializers.BooleanField(required=False, label='逻辑删除') hello = serializers.CharField() # 增加模型中不存在字段
- 进入Django shell模式
python manage.py shell
from book.models import BookInfo book = BookInfo.objects.get(id=1) book.hello = '666' from book.serializers import BookInfoSerializer serializer = BookInfoSerializer(book) serializer.data
关联对象序列化
- models.py
from django.db import models # Create your models here. # 准备书籍列表信息的模型类 class BookInfo(models.Model): # 创建字段,字段类型 name = models.CharField(max_length=20, verbose_name='名称') # verbose_name admin管理后台使用 pub_date = models.DateField(verbose_name='发布日期', null=True) readcount = models.IntegerField(default=0, verbose_name='阅读量') commentcount = models.IntegerField(default=0, verbose_name='评论量') is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') class Meta: db_table = 'bookinfo' # 指明数据库表名 verbose_name = '图书' # 在admin站点中显示的名称 def __str__(self): """定义每个数据对象的显示信息""" return self.name # 准备人物列表信息的模型类 class PeopleInfo(models.Model): # 定义一个有序字典 GENDER_CHOICES = ( (0, 'male'), (1, 'female') ) name = models.CharField(max_length=20, verbose_name='名称') gender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别') description = models.CharField(max_length=200, null=True, verbose_name='描述信息') is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') # 外键 ForeignKey # 系统会字典为外加添加 id # 外键的级联操作 1对多 (书籍对人物) # CASCADE:删除主表数据时连通一起删除外键表中数据 book = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') class Meta: db_table = 'peopleinfo' verbose_name = '人物信息'
- serializers.py
# -*- coding: utf-8 -*- # @Time : 2022/9/24 # @Author : 大海 from abc import ABC from rest_framework import serializers from book.models import BookInfo class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" name = serializers.CharField(max_length=20, label='名称') # label DRF接口页面展示使用 pub_date = serializers.DateField(label='发布日期', required=True) readcount = serializers.IntegerField(required=False, label='阅读量') commentcount = serializers.IntegerField(required=False, label='评论量') is_delete = serializers.BooleanField(required=False, label='逻辑删除') # hello = serializers.CharField() # 增加模型中不存在字段 class HeroInfoSerializer(serializers.Serializer): """英雄数据序列化器""" GENDER_CHOICES = ( (0, 'female'), (1, 'male') ) id = serializers.IntegerField(label='ID', read_only=True) name = serializers.CharField(label='名字', max_length=20) gender = serializers.ChoiceField(choices=GENDER_CHOICES, label='性别', required=False) description = serializers.CharField(label='描述信息', max_length=200, required=False, allow_null=True) is_delete = serializers.BooleanField(label='是否删除', required=False) # 默认序列化外键id # book = serializers.PrimaryKeyRelatedField(label='书籍', read_only=True) # 序列化关联模型的__str__方法返回值序列化 # book = serializers.StringRelatedField(label='书籍', read_only=True) # 关联模型序列化器所有字段序列化 book = BookInfoSerializer() # book = serializers.PrimaryKeyRelatedField(label='书籍', queryset=BookInfo.objects.all())
# book = serializers.PrimaryKeyRelatedField(label='书籍', read_only=True) 默认序列化外键id In [1]: from book.models import BookInfo,PeopleInfo In [2]: from book.serializers import BookInfoSerializer,HeroInfoSerializer In [3]: hero = PeopleInfo.objects.get(id=1) In [4]: serializer = HeroInfoSerializer(instance=hero) In [5]: serializer.data Out[5]: {'id': 1, 'name': '郭靖', 'gender': 1, 'description': '降龙十八掌', 'is_delete': False, 'book': 1} # book = serializers.StringRelatedField(label='书籍', read_only=True) 序列化关联模型的__str__方法返回值序列化 In [1]: from book.serializers import BookInfoSerializer,HeroInfoSerializer ...: ...: from book.models import BookInfo,PeopleInfo ...: ...: hero = PeopleInfo.objects.get(id=1) ...: ...: serializer = HeroInfoSerializer(instance=hero) In [2]: serializer.data Out[2]: {'id': 1, 'name': '郭靖', 'gender': 1, 'description': '降龙十八掌', 'is_delete': False, 'book': '射雕英雄传'} # book = BookInfoSerializer() In [1]: from book.serializers import BookInfoSerializer,HeroInfoSerializer ...: ...: from book.models import BookInfo,PeopleInfo ...: ...: hero = PeopleInfo.objects.get(id=1) ...: ...: serializer = HeroInfoSerializer(instance=hero) In [2]: serializer.data 关联模型序列化器所有字段序列化 Out[2]: {'id': 1, 'name': '郭靖', 'gender': 1, 'description': '降龙十八掌', 'is_delete': False, 'book': OrderedDict([('nam e', '射雕英雄传'), ('pub_date', '1980-05-01'), ('readcount', 12), ('commentcount', 34), ('is_delete', False)])}
反序列使用
- 进入Django shell模式
: data = { ...: 'name': '北漂纪实', ...: 'pub_date':'2022-12-10' ...: } In [2]: from book.serializers import BookInfoSerializer In [3]: serializer = BookInfoSerializer(data=data) In [4]: serializer.is_valid(raise_exception=True) # 调用序列化器校验方法 Out[4]: True In [5]: serializer.errors # 获取错误信息 Out[5]: {} In [6]: serializer.validated_data # 获取反序列化后的数据 Out[6]: OrderedDict([('name', '北漂纪实'), ('pub_date', datetime.date(2022, 12, 10))])
- 单个字段校验
class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" name = serializers.CharField(max_length=20, label='名称') # label DRF接口页面展示使用 pub_date = serializers.DateField(label='发布日期', required=True) readcount = serializers.IntegerField(required=False, label='阅读量') commentcount = serializers.IntegerField(required=False, label='评论量') is_delete = serializers.BooleanField(required=False, label='逻辑删除') # hello = serializers.CharField() # 增加模型中不存在字段 peopleinfo_set = serializers.PrimaryKeyRelatedField(many=True, read_only=True) # 序列化id # peopleinfo_set = HeroInfoSerializer(many=True) # 一关联多 需要指定many=true 全部值 def validate_name(self, value): """序列化器中单个字段校验""" if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的") return value
- shell 模式
from book.serializers import BookInfoSerializer In [2]: data = { ...: 'name': '北漂纪实', ...: 'pub_date':'2022-12-10' ...: } In [3]: serializer = BookInfoSerializer(data=data) serializer.is_valid(raise_exception=True) ...: ...: --------------------------------------------------------------------------- ValidationError Traceback (most recent call last) <ipython-input-5-c24be91bdde3> in <module> ----> 1 serializer.is_valid(raise_exception=True) 2 D:\Python39\lib\site-packages\rest_framework\serializers.py in is_valid(self, raise_exception) 233 234 if self._errors and raise_exception: --> 235 raise ValidationError(self.errors) 236 237 return not bool(self._errors) ValidationError: {'name': [ErrorDetail(string='图书不是关于Django的', code='invalid')]}
- serializers.py
class BookInfoSerializer(serializers.Serializer): """图书数据序列化器""" name = serializers.CharField(max_length=20, label='名称') # label DRF接口页面展示使用 pub_date = serializers.DateField(label='发布日期', required=True) readcount = serializers.IntegerField(required=False, label='阅读量') commentcount = serializers.IntegerField(required=False, label='评论量') is_delete = serializers.BooleanField(required=False, label='逻辑删除') # hello = serializers.CharField() # 增加模型中不存在字段 peopleinfo_set = serializers.PrimaryKeyRelatedField(many=True, read_only=True) # 序列化id # peopleinfo_set = HeroInfoSerializer(many=True) # 一关联多 需要指定many=true 全部值 def validate_name(self, value): """序列化器中单个字段校验 validate_<field_name> """ if 'django' not in value.lower(): raise serializers.ValidationError("图书不是关于Django的") return value def validate(self, attrs): """多个字段校验 attrs 传过来的数据 字典类型 """ bread = attrs['readcount'] bcomment = attrs['commentcount'] if bread < bcomment: raise serializers.ValidationError('阅读量小于评论量') return attrs def create(self, validated_data): """新建""" return BookInfo.objects.create(**validated_data) def update(self, instance, validated_data): """更新,instance为要更新的对象实例""" instance.name = validated_data.get('name', instance.name) instance.readcount = validated_data.get('readcount', instance.readcount) instance.commentcount = validated_data.get('commentcount', instance.commentcount) instance.save() return instance
- 修改
from book.serializers import BookInfoSerializer In [4]: from book.models import BookInfo In [5]: book = BookInfo.objects.get(id=5) In [6]: data = { ...: 'name': '北漂纪实007-django', ...: 'pub_date':'2022-12-10', ...: 'readcount': 20, ...: 'commentcount':10 ...: } In [7]: serializer = BookInfoSerializer(book,data) In [8]: serializer.is_valid(raise_exception=True) Out[8]: True In [9]: serializer.save() Out[9]: <BookInfo: 北漂纪实007-django>
模型类序列化器ModelSerializer
- 模型序列化器
from rest_framework import serializers from book.models import BookInfo class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo # 指定模型 fields = '__all__' # 指定序列化器包含所有字段
指定字段
- 使用fields来明确字段,__all__表名包含所有字段,也可以写明具体哪些字段,如
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = ['id', 'name', 'bpub_date']
- 使用exclude可以明确排除掉哪些字段
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo exclude = ['readcount']
- 指明只读字段
class BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment') read_only_fields = ('id', 'readcount')
- 修改选项参数
lass BookInfoSerializer(serializers.ModelSerializer): """图书数据序列化器""" class Meta: model = BookInfo fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment') extra_kwargs = { 'readcount': {'min_value': 0, 'required': True}, 'commentcount': {'min_value': 0, 'required': True}, }