目录
一、基本概念
此节了解即可,下一篇是重点实用篇
1.1 概念图解
- 序列化:将服务端数据结构类型(模型类对象)转换为客户端数据结构格式(字典、JSON)
- 反序列化:将客户端数据结构类型(字典、JSON)转换为服务端数据结构类型(模型类对象)
- 序列化器:封装了序列化和反序列化(含数据校验)的所有操作
1.2 序列化器类图继承关系
- Serializer类:类似Django的Form类,比较底层,可定制程度最高的类,需要高度定制DRF的序列化器的时候选择
- ModelSerializer类:封装化的序列化器,可定制程度较低,常规功能基本具备,常用
二、序列化器写法
2.1 示例表间关系
具体ORM生成请移步(点击此处)
2.2 序列化器字段
-
常规写法:
字段名=serializers.数据类型(字段选项)
-
特性:
- 按需写入
- GET方法:把需要提供给客户端的字段才写进来,字段选项细控
- POST\PUT\PATCH方法:需要客户端提供的字段才写进来,字段选项细控
- 字段对应:除模型声明属性(见2.3中StuSerializer),序列化器字段名定要和模型里的字段名相同
- 字段功能:用在反序列化阶段验证数据,序列化阶段写了的字段名才会返回给客户端
- 按需写入
-
字段选项通用参数
参数名称 说明 read_only 仅用于序列化输出,默认False,若为True则相当于同时设置了required=False write_only 仅用于反序列化输入,默认False,序列化时不输出该字段 required 反序列化时必须输入,默认True,否则报错 default 默认值,序列化实例时,如果实例中不存在值,则将使用默认值,设置则意味着required=False many 定义当前字段是否为可迭代对象,若为True,返回键值对为 "key": [value1,value2...]
,
默认为False,返回键值对"key": value1
allow_null 表明该字段是否允许传入None,默认False validators 应用于传入字段输入的验证器函数列表,并且会引发验证错误或仅返回 error_messages 包含错误代码为键,错误消息为值的字典 label 备注,用于HTML展示API页面时,显示的字段名称 -
字段选项常用参数
参数名称 作用 max_length 最大长度 min_lenght 最小长度 allow_blank 是否允许为空,不与allow_null同时使用 trim_whitespace 是否清除前后空白字符 max_value 最小值 min_value 最大值 -
字段写法(含默认设置)
字段意义 字段构造 注释 布尔 BooleanField() 默认为required=False,若需要需显式声明 布尔+None NullBooleanField() 字符串 CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) 对应CharField和TextField 邮箱 EmailField(max_length=None, min_length=None, allow_blank=False) 正则表达式 RegexField(regex, max_length=None, min_length=None, allow_blank=False) 数字字母短横线 SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ 网址 URLField(max_length=None, min_length=None, allow_blank=False) 整型 IntegerField(max_value=None, min_value=None) 浮点型 FloatField(max_value=None, min_value=None) 十进制 DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 允许的最大位数,decimal_palces: 小数位数,coerce_to_string返回字符串值,则设置为 True 外键字段 PrimaryKeyRelatedField(read_only=True, many=True) read_only=True或queryset=models.表名.objects.all()必须二选一,many选项若为可迭代对象则需要填 时间+日期 DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) 纯日期 DateField(format=api_settings.DATE_FORMAT, input_formats=None) 纯时间 TimeField(format=api_settings.TIME_FORMAT, input_formats=None) 选择字段 ChoiceField(choices) 对于文本选择,allow_blank 应该是首选,而对于数字或其他非文本选择,allow_null 应该是首选 复合选择字段 MultipleChoiceField(choices) 文件 FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) 图片 ImageField(max_length=None,allow_empty_file=False,
use_url=UPLOADED_FILES_USE_URL)
2.3 序列化操作
2.3.1 继承serializers的序列化器
- 文件位置:/api/serializers.py
- 代码:此序列化器仅包含序列化操作必要内容,完整写法见反序列化操作的序列化器
from rest_framework import serializers class StuSerializer(serializers.Serializer): '''Stu表序列器''' # 主键定义read_only属性,反序列化时此属性会被丢弃 id = serializers.IntegerField(read_only=True) name = serializers.CharField() # 外键字段之穷举法:调用外键所在表的序列器 stu_detail = StuDetailSerializer() # 外键字段之穷举法:调用外键所在表的序列器,many选项:一对多、多对多字段必须写 book = BookSerializer(many=True) ''' # 外键字段之主键法:只深入到外键所在表的主键,many选项:一对多、多对多字段必须写 stu_detail = serializers.PrimaryKeyRelatedField(read_only=True) # 视图显示结果均为 # stu序列器: {'id': 1, 'name': 'sam', 'stu_detail': 2, 'book': [1, 2], 'is_marked': True} ''' # 模型声明属性:此序列器字段不在数据库中,可自定义添加,返回响应后清除数据 is_marked = serializers.BooleanField(default=True) class StuDetailSerializer(serializers.Serializer): '''StuDetail表序列器''' id = serializers.IntegerField(read_only=True) birthday = serializers.DateField() height = serializers.DecimalField() # 可选项序列器字段写法 gender_choices = ( (0, 'female'), (1, 'male'), (2, 'secret'), ) gender = serializers.ChoiceField(choices=gender_choices) class BookSerializer(serializers.Serializer): '''Book表序列器''' id = serializers.IntegerField(read_only=True) name = serializers.CharField() publish = PublishSerializer() '''外键之反向跨表: stu_set = StuSerializer(many=True) 或下面这个 stu_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) 视图显示结果为 Book序列器: {'id': 2, 'name': 'chinese', 'publish': 2, 'stu_set': [1, 2]} ''' class PublishSerializer(serializers.Serializer): '''Publish表序列器''' id = serializers.IntegerField(read_only=True) name = serializers.CharField()
- 外键字段写法(PrimaryKeyRelatedField)
- 多对多字段名写法(隐式生成)
- 正向跨表:字段为:
外键名
,选项queryset, many=True
- 反向跨表:字段为:
外键所在表的表名小写_set
,选项read_only=True, many=True
- 表示法:上面两字段不可同时用穷举法,可同时用主键法,一穷一主,则穷举法在前
- 正向跨表:字段为:
- 一对多字段名写法
- 正向跨表: 字段为:
外键名
,选项queryset, many=False
- 反向跨表:字段为:
外键所在表的表名小写_set
,选项read_only=True, many=True
- 表示法:上面两字段不可同时用穷举法,可同时用主键法,一穷一主,则穷举法在前
- 正向跨表: 字段为:
一对多判定:外键所在的表为多,”多“表要加many=True
- 多对多字段名写法(隐式生成)
2.3.2 继承APIView的视图
- view.py代码
from rest_framework.views import APIView from rest_framework.response import Response from api import models, serializers class Test(APIView): def get(self, request): """序列化单个模型数据""" # 1、读取模型对象 student = models.Stu.objects.first() # 2、实例化序列化器(将模型类对象传给对应的序列化器) serializer = serializers.StuSerializer(instance=student) # 3、返回结果,通过data属性获取序列化器转换数据后的结果 print('stu序列器:', serializer.data) student_detail = models.StuDetail.objects.first() serializer = serializers.StuDetailSerializer(instance=student_detail) print('StuDetail序列器:', serializer.data) book = models.Book.objects.first() serializer = serializers.BookSerializer(instance=book) print('Book序列器:', serializer.data) """序列化多个模型数据""" # 1、读取模型对象(多个) publish = models.Publish.objects.all() # 2、实例化序列化器对象,many=True:告诉序列化器内部,instance值为列表,需循环遍历 serializer = serializers.PublishSerializer(instance=publish, many=True) # 3、返回结果,通过data属性获取序列化器转换数据后的结果 print('Publish序列器:', serializer.data) return Response("操作完成")
APIView内获取请求各部分方法:
- 获取请求头:
res = request.headers.get('Host')
,打印全部print(request.headers)
- get请求体:
res = request.query_params.get('id')
,打印全部print(request.query_params)
- put/post/delete请求体:
res = request.data.get('id')
,打印全部print(request.data)
- 列表:如果键值对的值为列表,需通过
res = request.data.getlist('id[]')
获取,id[]
由print(request.data)
查找对应值 - 前端axios请求封装:传送门第三节
- 获取请求头:
2.3.3 显示结果
- 有序字典OrderedDict:
- 释义
因为python内置的基础类型的字典是无序的,所以这种无序字典无法保证存储时的键值对顺序和提取时候的顺序一致,有序字典和无序字典,除了声明不一样以外,对于成员的读取和操作是一样的。 - 取值方法
for item in serializer.data: print(item["birthday"])
- 释义
- 结果
######################################################################### '''stu序列器:''' { 'id': 1, 'name': 'sam', 'stu_detail': OrderedDict( [ ('id', 2), ('birthday', '1987-08-08'), ('height','175.5'), ('gender', 2) ] ), 'book':[ OrderedDict( [ ('id', 1), ('name', 'math'), ('publish', OrderedDict( [ ('id', 2), ('name', 'social publisher') ] ) ) ] ), OrderedDict( [ ('id', 2), ('name', 'chinese'), ('publish', OrderedDict( [ ('id', 2), ('name', 'social publisher') ] ) ) ] ) ], 'is_marked': True } ######################################################################### '''StuDetail序列器:''' {'id': 1, 'birthday': '1999-12-09', 'height': '165.4', 'gender': 1} ######################################################################### '''Book序列器:''' { 'id': 1, 'name': 'math', 'publish': OrderedDict( [ ('id', 2), ('name', 'social publisher') ] ) } ######################################################################### '''Publish序列器:''' [ OrderedDict([('id', 1), ('name', 'central publisher')]), OrderedDict([('id', 2), ('name', 'social publisher')]) ]
2.4 反序列化操作
- 校验
- 数据类型校验:CharField等
- 选项校验:max_length等
- 入库:重写序列器create、update函数
2.4.1 继承serializers的序列化器
- 文件位置:/api/serializer.py
- 代码
from rest_framework import serializers from api import models class StuDetailSerializer(serializers.Serializer): '''StuDetail表序列器''' # 主键定义read_only属性,反序列化时此属性会被丢弃 id = serializers.IntegerField(read_only=True) birthday = serializers.DateField() # 十进制:精确计数,相对于浮点数:近似值 最大数位4,包含1个小数位 height = serializers.DecimalField(max_digits=4, decimal_places=1) # 可选项序列器ChoiceField字段写法 gender_choices = ( (0, 'female'), (1, 'male'), (2, 'secret'), ) gender = serializers.ChoiceField(choices=gender_choices) # 外键字段写法:外键所在的表为一对多中的“多”,需加many选项,用于标识可迭代对象 # PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset stu_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) def create(self, validated_data): # 常规模型新增数据:字典法,对应POST方法 studetail_obj = models.StuDetail.objects.create(**validated_data) # 返回给视图函数serializer.save() return studetail_obj def update(self, instance, validated_data): # get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法 # 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法 instance.birthday = validated_data.get("birthday", instance.birthday) instance.height = validated_data.get("height", instance.height) instance.gender = validated_data.get("gender", instance.gender) # 将修改后的数据提交数据库写入 instance.save() # 返回给视图函数serializer.save() return instance class PublishSerializer(serializers.Serializer): '''Publish表序列器''' id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=50) # 外键字段写法:外键所在的表为一对多中的“多”,需加many选项,用于标识可迭代对象 # PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset book_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) # book_set = BookSerializer(read_only=True, many=True) """自定义字段校验规则:重写validate方法""" def validate(self, attrs): # attrs为客户端传进来并被序列器处理过的字典 name = attrs['name'] if "0" in name: # 返回客户端 {"non_field_errors": ["名字不能包含字符0"} raise serializers.ValidationError("名字不能包含字符0") # 校验通过,则原样返回 return attrs def create(self, validated_data): # 常规模型新增数据:字典法,对应POST方法 pub_obj = models.Publish.objects.create(**validated_data) # 返回给视图函数serializer.save() return pub_obj def update(self, instance, validated_data): # get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法 # 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法 instance.name = validated_data.get("name", instance.name) # 将修改后的数据提交数据库写入 instance.save() # 返回给视图函数serializer.save() return instance class StuSerializer(serializers.Serializer): '''Stu表序列器''' # 主键定义read_only属性,反序列化时此属性会被丢弃 id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=12) # 外键字段写法:外键所在的表为一对多中的“多”,需加many选项,用于标识可迭代对象 # PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset stu_detail = serializers.PrimaryKeyRelatedField(queryset=models.StuDetail.objects.all(), many=False) # book为Stu表隐性生成的,正反向跨表由此判断 book = serializers.PrimaryKeyRelatedField(queryset=models.Book.objects.all(), many=True) def create(self, validated_data): # 常规模型新增数据:字典法,对应POST方法 # 弹出字典中的外键键值对,在create方法指定修改 stu_detail = validated_data.pop("stu_detail") # 弹出字典中的外键键值对,在add方法指定修改 book = validated_data.pop("book") # create方法:字典不可含外键id,可含外键object,若确需用id,须明确指定如下 stu_obj = models.Stu.objects.create(stu_detail=stu_detail, **validated_data) # add方法对应ORM数据库模型manytomany方法新增数据方法 stu_obj.book.add(*book) # 返回给视图函数serializer.save() return stu_obj def update(self, instance, validated_data): # get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法 # 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法 instance.name = validated_data.get("name", instance.name) instance.stu_detail = validated_data.get("stu_detail", instance.stu_detail) book = validated_data.get("book", instance.book) # set方法对应ORM数据库模型manytomany方法,重置外键,非新增 instance.book.set(book) # 将修改后的数据提交数据库写入 instance.save() # 返回给视图函数serializer.save() return instance class BookSerializer(serializers.Serializer): '''Book表序列器''' # 主键定义read_only属性,反序列化时此属性会被丢弃 id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=12) # 外键字段写法:外键所在的表为一对多中的“多”,需加many=True,用于标识可迭代对象 # PrimaryKeyRelatedField:反向跨表用read_only,正向跨表用queryset publish = serializers.PrimaryKeyRelatedField(queryset=models.Publish.objects.all(), many=False) stu_set = serializers.PrimaryKeyRelatedField(read_only=True, many=True) def create(self, validated_data): # 常规模型新增数据:字典法,对应POST方法 # 弹出字典中的外键键值对,在create方法指定修改 publish = validated_data.pop("publish") # create方法:字典不可含外键id,可含外键object,若确需用id,须明确指定如下 book_obj = models.Book.objects.create(publish=publish, **validated_data) # 返回给视图函数serializer.save() return book_obj def update(self, instance, validated_data): # get方法为Python的字典方法,正常取到字典的键birthday的值赋值:对应PUT方法 # 否则取instance.birthday给等号左侧instance.birthday赋值:对应PATCH方法 instance.name = validated_data.get("name", instance.name) instance.publish = validated_data.get("publish", instance.publish) # 将修改后的数据提交数据库写入 instance.save() # 返回给视图函数serializer.save() return instance
2.4.2 继承APIView的视图
- view.py代码
from rest_framework.views import APIView from rest_framework.response import Response from api import models, serializers class Test(APIView): # 查操作,按需打开,return只能返回最后一个serializer.data def get(self, request): """序列化操作,同2.3.1条""" """StuDetail表的序列化操作""" # stu_detail = models.StuDetail.objects.all() # serializer = serializers.StuDetailSerializer(instance=stu_detail, many=True) # print('StuDetail序列器:', serializer.data) """Publish表的序列化操作""" # publish = models.Publish.objects.all() # serializer = serializers.PublishSerializer(instance=publish, many=True) # print('Publish序列器:', serializer.data) """Stu表的序列化操作""" student = models.Stu.objects.all() serializer = serializers.StuSerializer(instance=student, many=True) print('stu序列器:', serializer.data) """Book表的序列化操作""" # book = models.Book.objects.all() # serializer = serializers.BookSerializer(instance=book, many=True) # print('Book序列器:', serializer.data) return Response(serializer.data) # 增操作 def post(self, request): """Studetail表的反序列化操作""" studetail_data = { "birthday": "1993-7-10", "height": 168, "gender": 1 } serializer = serializers.StuDetailSerializer(data=studetail_data) serializer.is_valid(raise_exception=True) serializer.save() """Publish表的反序列化操作""" publish_data = {"name": "publish of east"} serializer = serializers.PublishSerializer(data=publish_data) serializer.is_valid(raise_exception=True) serializer.save() """Stu表的反序列化操作""" stu_data = { "name": "jackson", "stu_detail": 4, "book": [1, 3] } serializer = serializers.StuSerializer(data=stu_data) serializer.is_valid(raise_exception=True) serializer.save() """Book表的反序列化操作""" book_data = { "name": "art", "publish": 2, } serializer = serializers.BookSerializer(data=book_data) serializer.is_valid(raise_exception=True) serializer.save() return Response("操作完成") # 改操作 def put(self, request): """Studetail表的反序列化操作""" # 模拟客户端提交来的json数据,后面补充 studetail_data = { "birthday": "1995-7-10", "height": 175, "gender": 2 } # 选定需要修改的模型对象 studetail_obj = models.StuDetail.objects.last() # 1、给序列化器传两个参数instance,data,表示修改,instance为数据库模型数据,data为客户提供数据 serializer = serializers.StuDetailSerializer(instance=studetail_obj, data=studetail_data) # 2、进行数据校验,raise_exception=True在反序列化时验证失败时抛出serializers.ValidationError # REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应 serializer.is_valid(raise_exception=True) # 3、数据入库,调用序列化器的update方法 serializer.save() """Publish表的反序列化操作""" publish_dic = {"name": "publish of west"} publish_object = models.Publish.objects.last() serializer = serializers.PublishSerializer(instance=publish_object, data=publish_dic) serializer.is_valid(raise_exception=True) serializer.save() """Stu表的反序列化操作""" stu_data = { "name": "jack", "stu_detail": 4, "book": [2, 3] } stu_obj = models.Stu.objects.last() serializer = serializers.StuSerializer(instance=stu_obj, data=stu_data) serializer.is_valid(raise_exception=True) serializer.save() """Book表的反序列化操作""" book_data = { "name": "sports", "publish": 1 } book_obj = models.Book.objects.last() serializer = serializers.BookSerializer(instance=book_obj, data=book_data) serializer.is_valid(raise_exception=True) serializer.save() return Response("操作完成") # 删操作 def delete(self, request): # 因为数据库模型外键有on_delete=models.CASCADE, # 所以以下数据删除有顺序,只能先删除有外键的表,再删除没有外键的表 """Book表的反序列化操作""" models.Book.objects.last().delete() """Publish表的反序列化操作""" models.Publish.objects.last().delete() """Stu表的反序列化操作""" last_stu = models.StuDetail.objects.last() # 清空多对多的中间表 last_stu.clear() last_stu.delete() """StuDetail表的反序列化操作""" models.StuDetail.objects.last().delete() return Response("操作完成") # 局部改操作(不需提供完整信息即可修改) def patch(self, request): """各表的反序列化操作""" # 与def put 相同,仅需修改以下一句即可(增加partial选项) # serializer=serializers.StuDetailSerializer(instance=studetail_obj,data=studetail_data,partial=True) return Response("操作完成")
APIView内获取请求各部分方法:
- 获取请求头:
res = request.headers.get('Host')
,打印全部print(request.headers)
- get请求体:
res = request.query_params.get('id')
,打印全部print(request.query_params)
- put/post/delete请求体:
res = request.data.get('id')
,打印全部print(request.data)
- 前端axios请求封装:传送门第三节
- 获取请求头: