Serializer的使用
【一】常用序列化字段和参数
【1】常见字段
字段 | 详解 | 字段构造方式 |
---|---|---|
BooleanField | 布尔字段用于存储和表示真/假值。构造方法不需要参数。 | BooleanField() |
NullBooleanField | 可空布尔字段是可以接受三个值的布尔字段:True、False和None(空值)。构造方法不需要参数。 | NullBooleanField() |
CharField | 字符字段用于存储短文本数据。max_length指定字符的最大长度,min_length指定最小长度。allow_blank指定是否允许为空值。trim_whitespace指定是否在保存数据前去除首尾的空格。 | CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) |
EmailField | Email字段用于存储和验证电子邮件地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 | EmailField(max_length=None, min_length=None, allow_blank=False) |
RegexField | 正则表达式字段用于存储和验证符合特定模式的数据。regex指定正则表达式,max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 | RegexField(regex, max_length=None, min_length=None, allow_blank=False) |
SlugField | Slug字段用于存储URL友好的文本标识符。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 | SlugField(max_length=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9_-]+ |
URLField | URL字段用于存储和验证URL地址。max_length指定最大字符长度,min_length指定最小长度。allow_blank指定是否允许为空值。 | URLField(max_length=200, min_length=None, allow_blank=False) |
UUIDField | UUID字段用于存储和验证通用唯一标识符。format参数指定UUID的格式。 | UUIDField(format='hex_verbose') format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "1234567012312313134124512351145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a" |
IPAddressField | IP地址字段用于存储和验证IP地址。protocol参数指定所允许的IP地址协议类型,unpack_ipv4参数指定是否拆分IPv4地址。 | IPAddressField(protocol='both', unpack_ipv4=False, **options) |
IntegerField | 整数字段用于存储整数值。max_value指定最大值,min_value指定最小值。 | IntegerField(max_value=None, min_value=None) |
FloatField | 浮点数字段用于存储浮点数值。max_value指定最大值,min_value指定最小值。 | FloatField(max_value=None, min_value=None) |
DecimalField | 十进制字段用于存储精确的十进制数值。max_digits指定最多位数,decimal_places指定小数点位置。coerce_to_string指定是否将值强制转化为字符串形式。max_value指定最大值,min_value指定最小值。 | DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置 |
DateTimeField | 日期时间字段用于存储日期和时间。format参数指定日期时间的输出格式,input_formats参数指定输入格式。 | DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None) |
DateField | 日期字段用于存储日期。format参数指定日期的输出格式,input_formats参数指定输入格式。 | DateField(format=api_settings.DATE_FORMAT, input_formats=None) |
TimeField | 时间字段用于存储时间。format参数指定时间的输出格式,input_formats参数指定输入格式。 | TimeField(format=api_settings.TIME_FORMAT, input_formats=None) |
DurationField | 持续时间字段用于存储一段时间的持续时间。构造方法不需要参数。 | DurationField() |
ChoiceField | 选择字段用于存储和验证预定义选项中的一个值。choices参数指定可选的选项值。 | ChoiceField(choices) choices与Django的用法相同 |
MultipleChoiceField | 多选字段用于存储和验证多个预定义选项中的值。choices参数指定可选的选项值。 | MultipleChoiceField(choices) |
FileField | 文件字段用于上传和保存文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用文件的URL路径。 | FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ImageField | 图片字段用于上传和保存图片文件。max_length指定文件名的最大长度,allow_empty_file指定是否允许为空文件。use_url指定是否使用图片的URL路径。 | ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL) |
ListField | 列表字段用于存储和验证列表类型的数据。child参数指定列表中元素的类型,min_length指定最小长度,max_length指定最大长度。 | ListField(child=, min_length=None, max_length=None) |
DictField | 字典字段用于存储和验证字典类型的数据。child参数指定字典中value的类型。 | DictField(child=) |
- 总结:常用字段
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 |
-
常用 参数
read_only write_only
【四】反序列化之校验(post增加,局部钩子,全局钩子)
- 序列化类
class BookSerializer(serializers.Serializer):
# 要序列化的字段
# required : 是否必填字段,默认为True,就是必填字段
id = serializers.IntegerField(required=False)
# allow_blank:传入的数据允许为空,默认不为空
# max_length: 限制字符串的最大长度
name = serializers.CharField(allow_blank=True,max_length=8)
# max_value:限制最大值
# min_value:限制最小值
# error_messages:自定义错误信息
price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
- 后端使用
# 新增
def post(self, request):
# 前端传入数据,通过request.data取到数据,将数据保存到数据库中
# 借助于序列化类,完成校验和反序列化
# data : 前端传入的数据
book_ser = BookSerializer(data=request.data)
# 校验数据
if book_ser.is_valid():
# 三层:字段自己的校验/全局钩子校验/局部钩子校验
# 校验通过,保存数据
# validated_data:校验通过的数据
# 新增字段限制条件 ---> 在序列化类中的字段中添加限制条件
after_data = book_ser.validated_data
else:
print(book_ser.errors) # 校验失败的错误打印出来
return Response({"code": 100, "msg": "成功"})
小结:反序列化有三层校验
-
字段自己的:写的字段参数:required/max_length ...
-
局部钩子:写在序列化类中的方法
- 方法名必须是 validate_字段名
def validate_name(self, name): if 'sb' in name: # 不合法,抛异常 raise ValidationError('书名中不能包含sb') else: return name
-
全局钩子:写在序列化类中的方法
- 方法名必须是 validate
def validate(self, attrs): price = attrs.get('price') name = attrs.get('name') if name == price: raise ValidationError('价格不能等于书名') else: return attrs
-
只有三层都通过,在视图类中:
- ser.is_valid(): 才是True,才能保存
【五】反序列化之保存(增加)
- 新增接口
- 数据校验后
- 调用序列化类的
.save()
方法 - 同时还要在序列化类中重写
create
方法
- 序列化类
class BookSerializer(serializers.Serializer):
# 要序列化的字段
# required : 是否必填字段,默认为True,必填字段
id = serializers.IntegerField(required=False)
# allow_blank:传入的数据允许为空,默认不为空
# max_length: 限制字符串的最大长度
name = serializers.CharField(allow_blank=True, max_length=8)
# max_value:限制最大值
# min_value:限制最小值
# error_messages:自定义错误信息
price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
def create(self, validated_data):
# validated_data 校验过后的数据
# **validated_data : 解耦,将数据打散
book = models.Book.objects.create(**validated_data)
return book
- 后端使用
# 新增
def post(self, request):
# 前端传入数据,通过request.data取到数据,将数据保存到数据库中
# 借助于序列化类,完成校验和反序列化
# data : 前端传入的数据
book_ser = BookSerializer(data=request.data)
# 校验数据
if book_ser.is_valid():
# 三层:字段自己的校验/全局钩子校验/局部钩子校验
# 校验通过,保存数据
# validated_data:校验通过的数据
# 新增字段限制条件 ---> 在序列化类中的字段中添加限制条件
after_data = book_ser.validated_data
ser.save() # 会保存数据,但是会报错,因为不知道要保存到哪张表中
return Response({"code": 100, "msg": "成功"})
else:
print(book_ser.errors) # 校验失败的错误
return Response({"code": 100, "msg": "失败", "error": book_ser.errors})
- 小结
- 序列化类中重写 create 方法
- 在后端逻辑中调用 save 方法
- 如果调用create方法,校验通过的 validated_data 数据不会自动传入
- 需要传入的数据
ser = BookSerializer(data=request.data)
【六】反序列化之保存(修改)
【1.0】指定字段修改数据
- 序列化类
class BookSerializer(serializers.Serializer):
# 要序列化的字段
# required : 是否必填字段,默认为True,必填字段
id = serializers.IntegerField(required=False)
name = serializers.CharField(allow_blank=True, max_length=8)
price = serializers.IntegerField(max_value=100, min_value=10, error_messages={"error": "价格必须在10-100之间"})
def update(self, instance, validated_data):
# instance : 需要修改的对象 --- book
# validated_data : 需要修改并且是校验过的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
# 修改完要保存数据
instance.save()
- 后端使用
class BookDetailView(APIView):
# 修改
def put(self, request, pk):
book = Book.objects.get(pk=pk)
#instance 就是 BookSerializer.objects.get(pk=1) 返回的对象。
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save() # 也会报错,需要重写 update 方法
return Response({"code": 100, "msg": "修改成功"})
else:
return Response({"code": 100, "msg": "修改失败", "error": book_ser.errors})
- 问题就是
- 在重写 update 方法的时候,需要一个个的去取字段然后做修改
- 当字段太多的时候,会大大影响效率
【七】多字段案例
- model表
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=32, db_index=True)
price = models.IntegerField(unique=True)
pub_date = models.DateField(auto_now=True)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField("Author")
def __str__(self):
return self.name
class Meta:
db_table = 'book'
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
def __str__(self):
return self.name
class Meta:
db_table = 'publish'
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
email = models.EmailField()
def __str__(self):
return self.name
class Meta:
db_table = 'author'
【1】多表关联反序列化(获取)
- serializer类
from rest_framework import serializers
class PublishSerializer(serializers.Serializer):
name = serializers.CharField()
addr = serializers.CharField()
class AuthorSerializer(serializers.Serializer):
name = serializers.CharField()
age = serializers.IntegerField()
email = serializers.EmailField()
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.IntegerField()
pub_date = serializers.DateField()
# 序列化
publish_detail = PublishSerializer(source='publish', read_only=True)
author_list = AuthorSerializer(many=True, source='authors', read_only=True)
# 反序列化
publish = PublishSerializer(write_only=True)
author = PublishSerializer( write_only=True)
- views.py
from django.shortcuts import render
from rest_framework.response import Response
from .serializer import BookSerializer
from rest_framework.views import APIView
from task_xu.models import Book
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
# BookSerializer实例来序列化查询
serializer = BookSerializer(instance=books, many=True)
return Response(serializer.data)
![image-20240412172703281](https://img2023.cnblogs.com/blog/3331555/202404/3331555-20240412172714595-2003949536.png)
【1】多表关联反序列化(保存)
- 不要有误区---》增加图书,只是增加图书,选择作者和出版社(传:id)
book_obj.add(*列表)
book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除。
book_obj.authors.clear() #清空被关联对象集合
book_obj.authors.set(列表) #先清空再设置
read_only write_only 控制序列化类中某些字段,只用来序列化或反序列化
- serializer类
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.DecimalField(max_digits=5, decimal_places=2)
publish_date = serializers.DateField(required=False,default=datetime.now)
#### 序列化的字段和反序列化字段不一致####
## 1 笨办法:再写个序列化类,单独用来反序列化
## 2 通过 read_only write_only 控制
# 这个字段用来做序列化
publish_detail = PublishSerializer(source='publish',read_only=True)
# 这个字段用来做序列化
authors_list = AuthorSerializer(source='authors', many=True,read_only=True)
# 反序列化字段--》只用来保存---》多表关联
publish=serializers.IntegerField(write_only=True) # 前端传入数字---》自动跟出版社id做对应
authors=serializers.ListField(write_only=True)
# 更新
def update(self, instance, validated_data):
# 这些值将用于后续的单独更新操作
publish_id = validated_data.pop('publish')
authors=validated_data.pop('authors')
# 使用instance直接作为filterDjango会自动提取并使用其主键值。
book_qs=Book.objects.filter(pk=instance.pk)
# 对非多对多关系字段的批量更新
book_qs.update(**validated_data,publish_id=publish_id)
# 获取查询集中的第一条记录
# < QuerySet[ < Book: asdas >] >
# instance = book_qs
instance=book_qs.first()
# 会在中间表中删除这些原有的关联记录,从而“清除”它们建立新的关联
instance.authors.set(authors)
return instance
- views.py
class BookDetailView(APIView):
def put(self, request, pk):
# obj = Book.objects.all().filter(pk=pk).first()
# 传入的instance是什么,到了 update中,instance就是什么
serializer = BookSerializer(instance=pk, data=request.data)
if serializer.is_valid():
serializer.save()
return Response('成功')
else:
return Response({'code': 100, 'msg': serializer.errors})