一 序列化介绍
作用:
1.序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2.反序列化,把客户端发送过来的数据,经过response以后变成字典,序列化器可以把字典转成模型
3.反序列化,完成数据校验功能,前端传入数据,存到数据库中
1.1继承APIView+Response实现publish的五个接口
class PublishView(APIView):
def get(self, request):
publish_list = Publish.objects.all()
l = []
for publish in publish_list:
l.append({'name': publish.name, 'addr': publish.addr})
return Response({'code': 100, 'msg': '查询所有成功', 'results': l})
def post(self, request):
# 如果是urlencoded编码,这种方式不行 publish = Publish.objects.create(**request.data)
publish = Publish.objects.create(name=request.data.get('name'), addr=request.data.get('addr'))
return Response({'code': 100, 'msg': '新增成功', 'results': {'name': publish.name, 'addr': publish.addr}})
class PublishDetailView(APIView):
def get(self, request, pk):
publish = Publish.objects.filter(pk=pk).first()
return Response(
{'code': 100, 'msg': '查询单条成功', 'results': {'name': publish.name, 'addr': publish.addr}})
def put(self, request, pk):
publish = Publish.objects.filter(pk=pk).first()
publish.name = request.data.get('name')
publish.addr = request.data.get('addr')
publish.save()
return Response({'code': 100, 'msg': '修改成功', 'result': {'name': publish.name, 'addr': publish.addr}})
def delete(self, request, pk):
Publish.objects.filter(pk=pk).delete()
return Response({'code': 100, 'msg': '删除成功'})
1.2 序列化的使用
我们可以使用def提供的序列化器,实现序列化,反序列化和数据校验
使用步骤
1.写个py文件,叫serializer.py
2.写个类,继承serializer.Serializer
3.在类中写要序列化的代码
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 序列化后的数据
二 序列化类的快速使用
视图类
为了能够更加方便区分,我们把视图类的五个方法分到两个类中
from .serializer import PublishSerializer # 导入我们写好的serializer文件
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
使用步骤
1.写序列化类:写三层规则
2.视图类中
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方法
3.修改功能,也要校验和保存
修改使用步骤
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,但是内部做了判断
五 序列化常用字段
序列化的常用字段除了CharField之外基本上与我们django中的model层中的字段基本一一对应
字段 | 字段构造方式 |
---|---|
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=) |
六 序列化字段常用参数
字段参数
# CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
max_length :校验,最大长度
min_length:校验最短长度
allow_blank:是否允许为空
trim_whitespace:去掉前后的空白
# DateTimeField(format=api_settings.DATETIME_FORMAT)
format:格式化成的样子
# IntegerField(max_value=None, min_value=None)
max_value :数字
min_value:数字
通用参数
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
-------------------------------------------------------
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器:validators=[方法],方法对该字段做校验
error_messages 包含错误编号与错误信息的字典
---------------
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息
七 序列化高级用法之定制返回字段
定制序列化返回的字段格式
方案一:在表模型中写,在序列化类中映射 (可以使用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": "北京"
}
model.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)
serializer.py
### 定制返回字段
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'