DRF之序列化组件
目录
一、序列化组件介绍
序列化类(组件)可以干的事:
- 序列化 qs对象,单个对象 做序列化给前端
- 反序列化数据校验:前端传入数据---> 校验数据是否合法
- 反序列化---> 前端传入数据,存到数据库中
- DRF(Django REST framework)是一个用于构建基于 Django 的 Web API 的强大框架。
- 在 DRF 中,序列化组件是其中一个核心组件,用于在 API 请求和响应中处理数据的转换和验证。
- 序列化组件的主要功能是将复杂的数据结构(例如模型对象)转换为可以序列化(序列化为 JSON、XML 等格式)和传输的数据,并且能够根据所需的数据结构对传入的数据进行反序列化,还原为程序可操作的对象。
二、序列化类的使用
1 写个py文件,叫serializer.py
2 写个类,继承serializers.Serializer
3 在类中写要序列化的字段from rest_framework import serializers class PublishSerializer(serializers.Serializer): # 写字段,要序列化的字段 name = serializers.CharField() addr = serializers.CharField() id = serializers.IntegerField()
4 在视图类中使用,完成序列化
多条 ser = PublishSerializer(instance=publish_list, many=True) ??? ? ser.data ?# 序列化后的数据 单条: ser = PublishSerializer(instance=publish) ??? ? ser.data ?# 序列化后的数据
- 参数
- instance : 实例(对象)
- data : 数据
- many=True : 如果是queryset对象,一般都是必须加
- many=False : 如果是 .first() 一般不写,默认不写是 False
- 序列化的结果
- data = book_ser.data
- 将 book_ser 转成字典 -- 列表套字典
- data的类型是
- <class 'rest_framework.utils.serializer_helpers.ReturnList'>
- data = book_ser.data
三、序列化类快速使用
视图类
from .serializer import PublishSerializer
class PublishView(APIView):
def get(self, request):
publish_list = Publish.objects.all()
ser = PublishSerializer(instance=publish_list, many=True)
# 如果序列化多条,要many=True
return Response({'code': 100, 'msg': '查询所有成功', 'results': ser.data})
class PublishDetailView(APIView):
def get(self, request, pk):
publish = Publish.objects.filter(pk=pk).first()
ser = PublishSerializer(instance=publish) # 单个不写many=True
return Response(
{'code': 100, 'msg': '查询单条成功', 'results': ser.data})
序列化类
from rest_framework import serializers
class PublishSerializer(serializers.Serializer):
# 写字段,要序列化的字段
name = serializers.CharField()
# addr = serializers.CharField()
id = serializers.IntegerField()
路由
urlpatterns = [
path('publish/', views.PublishView.as_view()),
path('publish/<int:pk>', views.PublishDetailView.as_view()),
]
四、?序列化类反序列化校验
序列化类可以做字段校验---> 三层
第一层:字段自己的serializers.CharField(max_length=12,min_length=3)
第二层:局部钩子
def validate_name(self, name):
# 待校验的前端传入的name的数据
if name.startswith("sb"):
# 不行,抛异常
raise ValidationError('不能以sb开头')
return name
全局钩子--> 前端多传的,这里不会有
def validate(self, attrs):
print(attrs)
# 多个字段同时校验
# 出版社名和地址不能一样---》出版社前3个字不能和地址前3个字一样
if attrs.get('name')[:3] == attrs.get('addr')[:3]:
raise ValidationError('出版社名和地址不能一样')
return attrs
【使用步骤】?
写序列化类:写三层规则
视图类中:
ser = PublishSerializer(data=request.data) ?# 把待校验数据传入
if ser.is_valid(): ?# 做数据校验---> 三层
print(ser.data)
else:
print(ser.errors) ?# 没有校验通过,打印错误信息
五、序列化类保存和修改
【保存】
1 在序列化类中,必须重写 create,完成真正的保存
"""保存,必须重写create"""
def create(self, validated_data):
# validated_data 校验过后的数据---》多传的数据,在这没有
publish = Publish.objects.create(**validated_data)
return publish ?
# 不要忘了返回新增的对象---> 后续会拿着这个对象做序列化 ?ser.data--->根据它做序列化的
2 在视图类中,数据校验通过后,调用ser.save()
ser.save() ?# 使用序列化类保存--> 会报错---> 我们没有指定保存到那个表--> 必须重写create方法
【修改】
修改功能,也要校验和保存
1 在序列化类中,必须重写 update,完成真正的修改
def update(self, instance, validated_data): ?# {name:上海出版社,add:上海地址}
instance.name = validated_data.get('name')
instance.addr = validated_data.get('addr')
instance.save() # publish 对象的save---> 保存到数据中
return instance
2 视图类中
?? ??? ?ser = PublishSerializer(instance=publish, data=request.data)
?? ??? ?ser.save() # 虽然新增或修改都是调用save,但是内部做了判断
六、常用序列化字段和参数
【1】常用字段
字段 | 字段构造方式 | 详解 |
---|---|---|
BooleanField | BooleanField() | 布尔字段用于存储和表示真/假值。构造方法不需要参数。 |
NullBooleanField | NullBooleanField() | 可空布尔字段是可以接受三个值的布尔字段:True、False和None(空值)。构造方法不需要参数。 |
CharField | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) | 字符字段用于存储短文本数据。max_length指定字符的最大长度,min_length指定最小长度。allow_blank指定是否允许为空值。trim_whitespace指定是否在保存数据前去除首尾的空格。 |
EmailField | EmailField(max_length=None, min_length=None, allow_blank=False) | Email字段用于存储和验证电子邮件地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 |
RegexField | RegexField(regex, max_length=None, min_length=None, allow_blank=False) | 正则表达式字段用于存储和验证符合特定模式的数据。regex指定正则表达式,max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值 |
SlugField | SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+ | Slug字段用于存储URL友好的文本标识符。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 |
URLField | URLField(max_length=200, min_length=None, allow_blank=False) | URL字段用于存储和验证URL地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 |
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" | UUID字段用于存储和验证通用唯一标识符。format参数指定UUID的格式。 |
IPAddressField | IPAddressField(protocol=’both’, unpack_ipv4=False, **options) | IP地址字段用于存储和验证IP地址。protocol参数指定所允许的IP地址协议类型,unpack_ipv4参数指定是否拆分IPv4地址。 |
IntegerField | IntegerField(max_value=None, min_value=None) | 整数字段用于存储整数值。max_value指定最大值,min_value指定最小值。 |
FloatField | FloatField(max_value=None, min_value=None) | 浮点数字段用于存储浮点数值。max_value指定最大值,min_value指定最小值。 |
DecimalField | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 | 十进制字段用于存储精确的十进制数值。max_digits指定最多位数,decimal_places指定小数点位置。coerce_to_string指定是否将值强制转化为字符串形式。max_value指定最大值,min_value指定最小值。 |
DateTimeField | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) | 日期时间字段用于存储日期和时间。format参数指定日期时间的输出格式,input_formats参数指定输入格式。 |
DateField | DateField(format=api_settings.DATE_FORMAT, input_formats=None) | 日期字段用于存储日期。format参数指定日期的输出格式,input_formats参数指定输入格式。 |
TimeField | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) | 时间字段用于存储时间。format参数指定时间的输出格式,input_formats参数指定输入格式。 |
DurationField | DurationField() | 持续时间字段用于存储一段时间的持续时间。构造方法不需要参数。 |
ChoiceField | ChoiceField(choices) choices与Django的用法相同 | 选择字段用于存储和验证预定义选项中的一个值。choices参数指定可选的选项值。 |
MultipleChoiceField | MultipleChoiceField(choices) | 多选字段用于存储和验证多个预定义选项中的值。choices参数指定可选的选项值。 |
FileField | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) | 文件字段用于上传和保存文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用文件的URL路径。 |
ImageField | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) | 图片字段用于上传和保存图片文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用图片的URL路径。 |
ListField | ListField(child=, min_length=None, max_length=None) | 列表字段用于存储和验证列表类型的数据。child参数指定列表中元素的类型,min_length指定最小长度,max_length指定最大长度。 |
DictField | DictField(child=) | 字典字段用于存储和验证字典类型的数据。child参数指定字典中value的类型。 |
- 总结:常用字段
IntegerField
CharField
DateTimeField
DecimalField
ListField和DictField
【2】常用参数
(1) 选项参数:(CharField,IntegerField)
参数名称 | 作用 |
---|---|
max_length | 校验,最大长度 |
min_lenght | 检验,最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 去掉前后的空白 |
max_value | 最小值 |
min_value | 最大值 |
(2) 通用参数
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
-------------------------------------------------------
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器:validators=[方法],方法对该字段做校验
error_messages 包含错误编号与错误信息的字典
---------------
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
- 常用参数
read_only
write_only
七、序列化高级用法之soruce
1 修改字段,映射字段
# publish_name表中不存在
publish_name = serializers.CharField(source='name')
2 修改字段,映射方法
# sb_name是表模型中一个方法
name = serializers.CharField(source='sb_name')
3 修改字段,跨表查询
# book表中可以链表查询
publish=models.ForeignKey(to='Publish.name')
八、序列化高级用法之定制返回字段
【1】多表关联序列化
# 定制序列化返回的字段格式
-方案一:在表模型中写,在序列化类中映射 (可以使用source)
# models.py
def publish_detail(self):
return {'name': self.publish.name, 'city': self.publish.city}
# serializer.py
publish_detail = serializers.DictField()
# 前端看到
"publish_detail": {
"name": "北京出版社",
"city": "北京"
}
-方案二:在序列化类中写SerializerMethodField,必须配合一个方法 get_字段名,方法返回什么,前端就看到什么
# Serializer.py
publish_detail = serializers.SerializerMethodField()
def get_publish_detail(self, obj):
return {'name': obj.publish.name, 'city': obj.publish.city}
# 前端看到
"publish_detail": {
"name": "北京出版社",
"city": "北京"
}
models.py
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField(to='Author')
def __str__(self):
return self.name
# def book_name(self):
# return self.name+'sb'
# def publish_detail(self):
# return {'name': self.publish.name, 'city': self.publish.city}
#
# def author_list(self):
# l = []
# for author in self.authors.all():
# l.append({'name': author.name, 'age': author.age})
# return l
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
def __str__(self):
return self.name
class AuthorDetail(models.Model):
telephone = models.BigIntegerField()
birthday = models.DateField()
addr = models.CharField(max_length=64)
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField()
def __str__(self):
return self.name
class Meta:
verbose_name = '出版社'
verbose_name_plural = verbose_name
views.py
class BookView(APIView):
def get(self, request):
obj = Book.objects.all()
ser = BookSerializer(instance=obj, many=True)
'''
[
{
"name": "西游记",
"price": "66.00",
"publish_detail": {name:名字,city:城市},
"authors_list":[{name:名字,age:19}]
},
]
'''
return Response(ser.data)
### 定制返回字段 ###
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
# 定制返回字段---》方案一:在表模型中写方法,在序列化类中做映射
# publish_detail = serializers.CharField() # publish_detail 会映射表模型中 publish_detail方法,方法返回值是 字典,强行用CharField字符串接收
# publish_detail = serializers.DictField() # publish_detail 会映射表模型中 publish_detail方法,方法返回值是 字典,用DictField接收
# author_list = serializers.ListField()
# 定制返回字段---》方案二:在序列化类中写 SerializerMethodField
# 只要写了这个字段类SerializerMethodField,必须配合一个方法:get_字段名,这个方法返回什么,前端这个字段就显示什么
publish_detail = serializers.SerializerMethodField()
def get_publish_detail(self, obj):
# 当前序列化到的book对象
return {'name': obj.publish.name, 'city': obj.publish.city}
author_list = serializers.SerializerMethodField()
def get_author_list(self, obj):
l = []
for author in obj.authors.all():
l.append({'name': author.name, 'age': author.age})
return l
book_name = serializers.SerializerMethodField()
def get_book_name(self, obj):
return obj.name + 'sb'
【2】多表关联反序列化
反序列化保存
使用同一个序列化类会出现
- 序列化字段和反序列化字段不一致
- 序列化字段:
- name
- price
- publish_detail
- author_list
- 反序列化字段:
- name
- price
- publish
- author
- 如果是共同的,不需要额外处理
- 如果是不同的,需要通过字段参数控制
- read_only?? ?表明该字段仅用于序列化输出,默认False,序列化过程
- write_only?? ?表明该字段仅用于反序列化输入,默认False,反序列化过程
serializer.py
class BookSerializer(serializers.Serializer):
name = serializers.CharField() # 公共的
price = serializers.CharField() # 公共的
publish = serializers.IntegerField(write_only=True) # 只用来做反序列化
authors = serializers.ListField(write_only=True) # 只用来做反序列化
publish_detail = serializers.SerializerMethodField(read_only=True) # 只用来做序列化
author_list = serializers.SerializerMethodField(read_only=True) # 只用来做序列化
def get_publish_detail(self, obj):
return {'name': obj.publish.name, 'city': obj.publish.city}
def get_author_list(self, obj):
l = []
for author in obj.authors.all():
l.append({'name': author.name, 'age': author.age})
return l
def create(self, validated_data):
# {name,price,publish:1,authors:[1,2]}
authors = validated_data.pop('authors')
book = Book.objects.create(name=validated_data.get('name'), price=validated_data.get('price'),
publish_id=validated_data.get('publish'))
book.authors.add(*authors)
return book
def update(self, instance, validated_data):
# {name,price,publish:1,authors:[1,2]}
authors = validated_data.pop('authors')
validated_data['publish_id'] = validated_data.pop('publish')
for key in validated_data:
setattr(instance, key, validated_data[key])
instance.save()
# 先清空在放入
# instance.authors.clear()
# instance.authors.add(*authors)
# 直接存
instance.authors.set(authors)
return instance
views.py
class BookView(APIView):
def post(self, request):
ser = BookSerializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
class BookDetail(APIView):
def put(self, request, pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
else:
return Response(ser.errors)
urls.py
urlpatterns = [
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetail.as_view()),
]
注:多表反序列化校验 --> 跟之前一样?
九、ModelSerializer使用
之前写的序列化类,继承了serializers.Serializer,跟表没有必然联系
ModelSerializer跟表一一对应,以后基本需要重写create和update
serializer.py
### 继承ModelSerializer --->少写代码
class BookSerializer(serializers.ModelSerializer):
# name = serializers.CharField(max_length=18,min_length=3) # 公共的
# price = serializers.CharField() # 公共的
# publish = serializers.IntegerField(write_only=True) # 只用来做反序列化
# authors = serializers.ListField(write_only=True) # 只用来做反序列化
# 上述操作,通过 Meta实现了
# 扩写的字段,也要在fields注册
# 方式二:定制字段
# publish_detail = serializers.SerializerMethodField(read_only=True) # 只用来做序列化
# author_list = serializers.SerializerMethodField(read_only=True) # 只用来做序列化
# def get_publish_detail(self, obj):
# return {'name': obj.publish.name, 'city': obj.publish.city}
# def get_author_list(self, obj):
# l = []
# for author in obj.authors.all():
# l.append({'name': author.name, 'age': author.age})
# return l
# 方式二:定制字段方式一
# publish_detail = serializers.DictField(read_only=True)
# author_list = serializers.ListField(read_only=True)
class Meta:
model = Book # 写了这两句,会把表模型中Book,所有字段映射过来
# fields='__all__'
fields = ['name', 'price', 'publish', 'authors', 'publish_detail', 'author_list']
extra_kwargs = { # 给某个或某几个字段设置字段属性
'name': {'max_length': 18, 'min_length': 3},
'publish': {'write_only': True},
'authors': {'write_only': True},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
}
# 一般不需要写create和update了---> ModelSerializer帮我们实现了
# 局部钩子和全局钩子,该怎么写还怎么写
# def validate_name(self,name):
# pass
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!