【二】序列化组件
【1】序列化与反序列化的概念
-
序列化(Serialization):将对象转换为可传输或可存储的格式的过程。在序列化过程中,对象的属性和数据被转换为一个字节流或字符串,以便在网络上传输或保存到文件中。常见的序列化格式包括 JSON、XML、Protocol Buffers 等。序列化后的数据可以在不同的系统、编程语言或应用程序之间进行交换和共享。
-
反序列化(Deserialization):将序列化后的数据恢复为原始对象的过程。在反序列化过程中,从序列化格式(例如 JSON 字符串)中解析出对象的属性和数据,并重新构建原始对象。反序列化的过程与序列化过程相反,它将序列化后的数据转换回原始对象,以便进行进一步的处理、操作或显示。
-
简单来说:
【2】序列化类(Serializer)
【2.1】定义序列化类
| |
| from rest_framework import serializers |
| |
| '''简单示例''' |
| class MySerializer(serializers.Serializer): |
| 字段名 = serializers.字段类型(字段参数) |
| |
| '''实例''' |
| class SnippetSerializer(serializers.Serializer): |
| id = serializers.IntegerField(read_only=True) |
| title = serializers.CharField(required=False, allow_blank=True, max_length=100) |
| |
| def create(self, validated_data): |
| """ |
| 根据提供的验证过的数据创建并返回一个新的`Snippet`实例。 |
| """ |
| return Snippet.objects.create(**validated_data) |
| |
| def update(self, instance, validated_data): |
| """ |
| 根据提供的验证过的数据更新和返回一个已经存在的`Snippet`实例。 |
| """ |
| instance.title = validated_data.get('title', instance.title) |
| return instance |
- 序列化器类的第一部分定义了序列化/反序列化的字段。
create()
和update()
方法定义了在调用serializer.save()
时如何创建和修改完整的实例。
【2.2】常见字段及参数
【2.2.1】常用字段类型
字段 |
字段构造方式 |
BooleanField |
BooleanField() |
NullBooleanField |
NullBooleanField() |
CharField |
CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField |
EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField |
RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField |
SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ |
URLField |
URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField |
UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField |
IPAddressField(protocol=’both’, unpack_ipv4=False, **options) |
IntegerField |
IntegerField(max_value=None, min_value=None) |
FloatField |
FloatField(max_value=None, min_value=None) |
DecimalField |
DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField |
DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField |
DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField |
TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField |
DurationField() |
ChoiceField |
ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField |
MultipleChoiceField(choices) |
FileField |
FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField |
ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField |
ListField(child=, min_length=None, max_length=None) |
DictField |
DictField(child=) |
【2.2.2】选项参数
参数名称 |
作用 |
max_length |
最大长度 |
min_lenght |
最小长度 |
allow_blank |
是否允许为空 |
trim_whitespace |
是否截断空白字符 |
max_value |
最小值 |
min_value |
最大值 |
【2.2.3】通用参数
参数名称 |
说明 |
read_only |
表明该字段仅用于序列化输出,默认False |
write_only |
表明该字段仅用于反序列化输入,默认False |
required |
表明该字段在反序列化时必须输入,默认True |
default |
反序列化时使用的默认值 |
allow_null |
表明该字段是否允许传入None,默认False |
validators |
该字段使用的验证器 |
error_messages |
包含错误编号与错误信息的字典 |
label |
用于HTML展示API页面时,显示的字段名称 |
help_text |
用于HTML展示API页面时,显示的字段帮助提示信息 |
【3】序列化类的基本操作
【3.1】序列化
| |
| from xx import Serializer |
| |
| ser = Serializer(instance=obj对象,data=request.data,...) |
| |
| ser.data |
【3.1.1】序列化对象的常用参数
- instance:要序列化的模型实例。如果需要对现有对象进行序列化,则传递该实例。
- data:要反序列化的数据。如果需要从数据中创建对象,则传递该数据。通常用于创建或更新对象。
- context:上下文数据,可以在序列化器的各个方法中使用。通常用于在序列化器之间传递额外的信息。
- many:指定是否序列化多个对象。默认为 False。如果设置为 True,则可以序列化多个对象的查询集。
- partial:指定是否部分更新对象。默认为 False。如果设置为 True,则可以部分更新对象而不需要提供所有字段的值。
【3.2】反序列化校验
- 序列化器在反序列化时通常会执行一系列验证操作,以确保输入的数据符合预期的格式和约束。
- 这些验证功能可以帮助确保用户提供的数据是有效的,并且可以在存储到数据库之前进行预处理。
【3.2.1】校验级别
【3.2.1.1】字段级别的验证
| class BookSerializer(serializers.Serializer): |
| name = serializers.CharField(min_length=5, max_length=32, error_messages={ |
| 'min_length': '最少不得少于5个字符', |
| 'max_length': '最多不得多于32个字符' |
| }) |
| price = serializers.IntegerField(min_value=10, max_value=999, error_messages={ |
| 'min_value': '最少不得少于10元', |
| 'max_value': '最多不得多于999元' |
| }) |
| publish = serializers.CharField(min_length=3, max_length=255, error_messages={ |
| 'min_length': '最少不得少于3个字符', |
| 'max_length': '最多不得多于255个字符' |
| }) |
【3.2.1.2】自定制校验器validators
- 与forms组件一样,可以指定
validators
参数自定制验证器
| def func(value): |
| '''验证数据格式''' |
| if xxx: |
| |
| |
| raise ValidationError("错误信息") |
| return value |
| |
| class MySerializer(serializers.Serializer): |
| |
| name = serializers.CharField(max_length=32,validators=[func,func2...]) |
【3.2.1.3】钩子函数
- 局部钩子:
validate_字段(self,字段)
- 全局钩子:
validate(self,attrs)
- 校验失败 抛出指定异常
ValidationError
from rest_framework.exceptions import ValidationError
| |
| def validate_task_name(self, name: str): |
| if 'sb' in name: |
| |
| raise ValidationError('不得包含侮辱性词汇') |
| |
| return name |
| |
| |
| def validate(self, attrs): |
| if attrs.get('name') == attrs.get('publish'): |
| raise ValidationError('书名不得与出版社名一致') |
| |
| return attrs |
【3.2.2】校验完成的数据 校验失败的错误信息
-
ser.is_valid()
:返回布尔值,True表示所有数据验证通过,False表示有错误数据
- 通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应
-
ser.data
:包含了序列化后字段及其对应数值的字典,可以直接用于生成 JSON 或其他格式的响应数据
-
ser.errors
:校验失败的错误提示信息,由error_message
参数指定或使用默认
| |
| '''不需要携带参数的视图类''' |
| class BookViewCR(APIView): |
| def get(self, request): |
| book_all = Book.objects.all() |
| |
| ser = BookSerializer(instance=book_all, many=True) |
| |
| return Response({'code': 100,'msg': 'get','results': ser.data}) |
| |
| def post(self, request): |
| data = request.data |
| |
| ser = BookSerializer(data=data) |
| if ser.is_valid(): |
| |
| |
| ser.save() |
| return Response({'code': 100, 'msg': '添加成功', 'result': ser.data}) |
| else: |
| |
| |
| return Response({'code': 101, 'msg': ser.errors}) |
| |
| '''需要携带 pk 参数 的视图类''' |
| class BookViewRUD(APIView): |
| |
| def get(self, request, tid): |
| |
| book = Book.objects.filter(pk=tid).first() |
| if not book: |
| return Response({'code': 101, 'msg': '当前书籍不存在'}) |
| |
| ser = BookSerializer(instance=book) |
| |
| return Response({'code': 100, 'msg': f'查询指定【{tid}】成功', 'result': ser.data}) |
| |
| |
| def put(self, request, tid): |
| |
| book = Book.objects.filter(pk=tid).first() |
| if not book: |
| return Response({'code': 101, 'msg': '当前书籍不存在'}) |
| |
| ser = BookSerializer(instance=book, data=request.data) |
| if ser.is_valid(): |
| |
| |
| ser.save() |
| return Response({'code': 100, 'msg': f'修改指定【{tid}】成功', 'result': ser.data}) |
| else: |
| |
| return Response({'code': 101, 'msg': ser.errors, }) |
【3.2】反序列化保存 create
update
- 序列化器判断是新建对象还是更新对象的标准就是,是否传递了
instance
参数,数据将由data
参数接受
| class xxx(serializers.Serializer): |
| |
| def create(self, validated_data): |
| '''可以对校验过的数据进行再次处理''' |
| |
| book = Book.objects.create(**validated_data) |
| ''' |
| title = validated_data.pop('title') |
| title += '爆款' |
| # 为标题加上爆款二字 |
| Book.objects.create(**validated_data,title=title) |
| ''' |
| return book |
| |
| def update(self, instance, validated_data): |
| |
| |
| for key in validated_data.keys(): |
| setattr(instance, key, validated_data.get(key)) |
| instance.save() |
| |
| return instance |
【3.2.1】save(**kwargs)
- 对序列化器进行
save()
保存时,可以额外传递数据,这些数据可以在create()
和update()
中的validated_data
参数获取到
| |
| class MyView(APIView): |
| def post(self,request): |
| ser = Ser(data=reuqest.data) |
| ser.is_valid(raise_exception=True) |
| ser.save(other='xxx') |
| |
| |
| |
| class Ser(serializer.Serializer): |
| ... |
| def create(self,validated_data): |
| other = validated_data.pop('other') |
| ... |
【4】source参数
source
参数用于指定要序列化的字段的源。通常,它用于在序列化器中访问模型实例的属性或方法,并将其值包含在序列化后的数据中。
- 当你需要访问模型实例的属性或方法,并将其值序列化到响应中时,可以使用
source
参数来指定该属性或方法的名称。这个参数告诉序列化器从哪里获取数据以进行序列化。
【4.1】source参数跨表查询
| |
| class Books(models.Model): |
| name = models.CharField(max_length=64) |
| price = models.DecimalField(max_digits=5, decimal_places=2) |
| |
| publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) |
| |
| |
| |
| |
| class Ser(serializers.Serializer): |
| ... |
| '''可以指定返回外键字段对象所对应的属性值''' |
| publish_name = serializers.CharField(source='publish.name') |
| publish_addr = serializers.CharField(source='publish.addr') |
| |
| '''更改字段序列化时显示的名称''' |
| book_name = serializers.CharField(source='title') |
【4.2】source参数指定执行模型表中的方法
| '''指定执行模型表中的方法''' |
| |
| class Task(models.Model): |
| name = models.CharField(max_length=32) |
| desc = models.CharField(max_length=32) |
| |
| def name2desc(self): |
| '''执行一些代码''' |
| return self.name + self.desc |
| |
| |
| |
| class TaskSer(serializers.Serializer): |
| |
| name_desc = serializers.CharField(source='name2desc') |
【4.3】source参数指定显示模型表中字段名称
| |
| class Task(models.Model): |
| name = models.CharField(max_length=32) |
| desc = models.CharField(max_length=32) |
| |
| |
| |
| class TaskSer(serializers.Serializer): |
| |
| task_name = serializers.CharField(source='name') |
【4.4】总结
| |
| |
| from rest_framework import serializers |
| |
| class TaskSer(serializers.Serializer): |
| |
| name = serializers.CharField() |
| |
| task_name = serializers.CharField(source='name') |
| |
| name2desc = serializers.CharField() |
| |
| name_desc = serializers.CharField(source='name2desc') |
| |
| user = serializers.CharField() |
| |
| user_name = serializers.CharField(source='user.username') |
| |
| |
| |
| |
| class Task(models.Model): |
| name = models.CharField(max_length=32) |
| desc = models.CharField(max_length=32) |
| user = models.ForeignKey(to='User', on_delete=models.CASCADE, default=1) |
| |
| def name2desc(self): |
| '''执行一些代码''' |
| return self.name + self.desc |
| |
| |
| class User(models.Model): |
| username = models.CharField(max_length=32, default='aaa') |

【5】使用 SerializerMethodField 定制字段
| |
| 字段 = serializers.SerializerMethodField() |
| def get_字段(self,obj): |
| '''此处的obj就是当前正在序列化的模型表对象''' |
| return ... |
| class TaskSer(serializers.Serializer): |
| |
| name = serializers.CharField() |
| desc = serializers.CharField() |
| |
| user_name = serializers.CharField(source='user.username') |
| xxx = serializers.SerializerMethodField() |
| |
| def get_xxx(self, obj): |
| ''' |
| 此处的self为序列化类的对象,应当返回模型对象中的数据 |
| :param obj: 当前模型表对象 |
| :return: 想要展示的值 |
| ''' |
| return obj.desc + '这是描述哟' |

【6】使用 子序列化 定制字段
| class UserSer(serializers.Serializer): |
| '''user表的序列化类''' |
| username = serializers.CharField() |
| |
| |
| class TaskSer(serializers.Serializer): |
| |
| name = serializers.CharField() |
| desc = serializers.CharField() |
| |
| |
| user = UserSer() |
| |
| user_obj = UserSer(source='user') |

- 如果既不使用与外键字段同名,且不使用source参数指定,将会报错
【7】ListField和DictField
ListField
用于序列化和反序列化列表类型的数据。
- 当你序列化数据时,
ListField
会将列表中的每个元素序列化为相应的格式,例如 JSON 数组
- 当你反序列化时,
ListField
字段将可以接受数组类型的数据
DictField
用于序列化和反序列化字典类型的数据。
- 当你序列化数据时,
DictField
会将字典中的键值对序列化为相应的格式,例如 JSON 对象。
- 当你反序列化时,
DictField
字段将可以接受字典类型的数据
【7.1】序列化使用场景
- 在模型表中,定义某些方法,返回列表或字典格式
- 【注】对于多对多字段,不能直接使用
ListField
来进行序列化,可以使用
SerializerMethodField
定义方法
- 在模型表中定义方法返回列表
- 使用子序列化并传递
many=True
| |
| class Task(models.Model): |
| name = models.CharField(max_length=32) |
| desc = models.CharField(max_length=32) |
| user = models.ForeignKey(to='User', on_delete=models.CASCADE, default=1) |
| |
| def num_list(self): |
| return [1, 2, 3] |
| |
| def info_dic(self): |
| return {'id': 1, 'username': self.user.username} |
| |
| |
| |
| class TaskSer(serializers.Serializer): |
| |
| name = serializers.CharField() |
| desc = serializers.CharField() |
| |
| l_str = serializers.CharField(source='num_list') |
| |
| l = serializers.ListField(source='num_list') |
| |
| num_list = serializers.ListField() |
| |
| info_dic = serializers.DictField() |
| dic = serializers.DictField(source='info_dic') |

| class TaskSer(serializers.Serializer): |
| |
| name = serializers.CharField() |
| desc = serializers.CharField() |
| |
| |
| |
| |
| user_list = serializers.SerializerMethodField() |
| |
| def get_user_list(self, obj): |
| return [user.username for user in obj.user.all()] |
| |
| |
| user_list2 = UserSer(source='user', many=True) |
【7.2】反序列化使用场景
| |
| class Task(models.Model): |
| name = models.CharField(max_length=32) |
| desc = models.CharField(max_length=32) |
| user = models.ManyToManyField(to='User') |
| |
| |
| class User(models.Model): |
| username = models.CharField(max_length=32, default='aaa') |
| |
| |
| |
| |
| class TaskSer(serializers.Serializer): |
| |
| name = serializers.CharField() |
| desc = serializers.CharField() |
| |
| |
| user = serializers.ListField(write_only=True) |
| |
| |
| |
| task_info = serializers.DictField(write_only=True) |
| |
| |
| |
| def create(self, validated_data): |
| |
| |
| print(validated_data) |
| |
| return validated_data |
| |
| |
| |
| class TaskView(APIView): |
| def get(self, request): |
| ser = TaskSer(Task.objects.all(), many=True) |
| return Response(ser.data) |
| |
| def post(self, request): |
| ser = TaskSer(data=request.data) |
| |
| ser.is_valid(raise_exception=True) |
| |
| ser.save() |
| return Response(ser.data if ser.is_valid() else ser.errors) |

【8】read_only
和write_only
- 当我们希望某些字段只执行序列化,也就是返回给前端时,可以使用
read_only
- 当我们希望某些字段只执行反序列化,也就是要求前端传值交由我们保存,可以使用
write_only
- 默认不填代表着,该字段既做序列化又做反序列化
| class TaskSer(serializers.Serializer): |
| |
| name = serializers.CharField() |
| desc = serializers.CharField() |
| |
| |
| user = UserSer(many=True, read_only=True) |
| |
| |
| user_l = serializers.ListField(write_only=True) |
| task_info = serializers.DictField(write_only=True) |


【补充】其他知识
【1】字段参数validators
- 在字段中添加validators选项参数,可以补充验证行为,如
| def about_django(value): |
| if 'django' not in value.lower(): |
| raise serializers.ValidationError("图书不是关于Django的") |
| |
| class BookInfoSerializer(serializers.Serializer): |
| """图书数据序列化器""" |
| title = serializers.CharField(label='名称', max_length=20, validators=[about_django]) |
| pub_date = serializers.DateField(label='发布日期', required=False) |
| read = serializers.IntegerField(label='阅读量', required=False) |
| comment = serializers.IntegerField(label='评论量', required=False) |
| image = serializers.ImageField(label='图片', required=False) |
【2】反序列化校验的三层校验
- 执行字段内部的校验
- max_length / min_length 等
- validators :是一个列表,可以传多个校验函数,将会依次执行列表中的所有校验函数
- 执行局部钩子:
validate_字段
- 执行全局钩子:
validate
【3】无法直接使用source参数反向查询
- 直接使用
source
参数是无法实现复杂的反向查询的。source
参数通常用于简单的字段访问,例如直接从模型实例的属性中获取数据。
- 如果需要进行复杂的反向查询,例如从关联模型中获取相关对象列表,需要使用
SerializerMethodField
并定义一个方法来实现
【9】模型类序列化类(ModelSerializer)
- DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个Serializer类。
- ModelSerializer与常规的Serializer相同,但提供了:
- 基于模型类自动生成一系列字段
- 基于模型类自动为Serializer生成validators,比如unique_together
- 包含默认的create()和update()的实现
| from rest_framework.serializers import ModelSerializer |
| |
| class XXX(ModelSerializer): |
| |
| 字段 = serializers.CharField() |
| class Meta: |
| |
| model=对应的表 |
| |
| fields = 需要使用的字段 |
| |
| extra_kwargs = { |
| '字段':{'额外添加的参数'} |
| } |
| |
| from .models import Task |
| |
| |
| class TaskSerV2(serializers.ModelSerializer): |
| |
| user_l = serializers.ListField(write_only=True) |
| task_info = serializers.DictField(write_only=True) |
| aaa = serializers.CharField(source='name') |
| |
| class Meta: |
| model = Task |
| fields = '__all__' |
| |
| extra_kwargs = { |
| 'name': {'max_length': 10} |
| } |
| |
| '''如果所需字段就是表中需要的,就不需要重写create方法了''' |
| def create(self, validated_data): |
| |
| validated_data.pop('user_l') |
| validated_data.pop('task_info') |
| |
| task = super().create(validated_data) |
| return task |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了