九、序列化器
9.1序列化
从数据库取QuerySet或数据对象转换成JSON
9.1.1序列化器的简易使用
python
#新建一张部门表
class Depart(models.Model):
title=models.CharField(verbose_name='部门',max_length=32)
order=models.IntegerField(verbose_name='顺序')
count=models.IntegerField(verbose_name='人数')
python
#新建路由
urlpatterns = [
path('api/<str:version>/depart/',views.DepartView.as_view(),name='depart'),
]
python
#创建一个序列化器
from rest_framework import serializers
class DepartSerializers(serializers.Serializer):
#部门系列化器,字段需要和数据库中的字段相对应
title=serializers.CharField()
order=serializers.IntegerField()
count=serializers.IntegerField()
python
#创建视图类
class DepartView(APIView):
#无需认证
authentication_classes = []
#部门视图类
def get(self,request,*args,**kwargs):
#1、获取数据库中的数据
depart_obj=models.Depart.objects.all().first()
#2、序列化器转换成JSON
ser_obj=DepartSerializers(instance=depart_obj)
#打印ser_obj.data类型
print('ser_obj.data.type:',type(ser_obj.data))
#3、返回给用户
context={
'status':True,
'data':ser_obj.data
}
return Response(context)
使用postman发送get请求进行测试
打印输出ser_obj.data的类型,是一个字典
python
ser_obj.data.type: <class 'rest_framework.utils.serializer_helpers.ReturnDict'>
9.1.2序列化QuerySet列表(多个数据对象)
python
#视图类
class DepartView(APIView):
#无需认证
authentication_classes = []
#部门视图类
def get(self,request,*args,**kwargs):
#1、获取数据库中的数据
#获取表中的所有记录(多个数据对象,是一个QuerySet列表)
depart_objs=models.Depart.objects.all()
#2、序列化器转换成JSON,many代表允许多个数据对象
ser_obj=DepartSerializers(instance=depart_objs,many=True)
print('ser_obj.data.type:',type(ser_obj.data))
#3、返回给用户
context={
'status':True,
'data':ser_obj.data
}
return Response(context)
使用postman发送GET请求进行测试
打印输出ser_obj.data的类型,是一个列表
python
ser_obj.data.type: <class 'rest_framework.utils.serializer_helpers.ReturnList'>
9.1.3ModelSerializer
python
#创建序列化器
from rest_framework import serializers
class DepartSerializers(serializers.ModelSerializer):
#部门系列化器
class Meta:
model = models.Depart
#获取数据库中的所有字段
fields = "__all__"
#指定字段
# fields = ['title','order','count']
#排除字段
# exclude=['count']
这个效果同9.2.2中的效果
9.1.4特殊字段的处理
python
#表结构
class Depart(models.Model):
#部门表
title=models.CharField(verbose_name='部门',max_length=32)
order=models.IntegerField(verbose_name='顺序')
count=models.IntegerField(verbose_name='人数')
class userInfo(models.Model):
#员工信息表
name=models.CharField(verbose_name='姓名',max_length=32)
GENDER_CHOICES=(
(1,'男'),
(2,'女')
)
#choices字段
gender = models.SmallIntegerField(verbose_name='性别', choices=GENDER_CHOICES)
#ForeignKey字段
depart=models.ForeignKey(verbose_name='部门',to=Depart,on_delete=models.CASCADE)
#DateTime字段
ctime=models.DateTimeField(verbose_name='创建时间',auto_now=True)
python
#创建路由
urlpatterns = [
path('api/<str:version>/depart/',views.DepartView.as_view(),name='depart'),
path('api/<str:version>/userinfo/',views.userInfoView.as_view(),name='userinfo'),
]
python
#序列化器类
class UserInfoSerializers(serializers.ModelSerializer):
#部门系列化器
#新增一个choices字段,并获取choices中的文本
gender_text=serializers.CharField(source='get_gender_display')
#新增一个ForeignKey字段,并获取关联表中的文本
depart_text=serializers.CharField(source='depart.title')
#修改ctime类,并进行格式化
ctime=serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
#新增一个数据库中不存在的字段
xxx=serializers.SerializerMethodField()
class Meta:
model = models.userInfo
fields = ['name','gender','gender_text','depart','depart_text','ctime','xxx']
def get_xxx(self,obj):
#这个函数返回什么,xxx这个字段就等于什么。
#obj代表当前数据对象,obj.name就是当前数据对象中的name字段值
return 'I am {}'.format(obj.name)
python
#视图类
class userInfoView(APIView):
# 用户视图类
# 无需认证
authentication_classes = []
def get(self, request, *args, **kwargs):
# 1、获取数据库中的数据
# 多条数据
userInfo_objs = models.userInfo.objects.all()
# 2、序列化器转换成JSON,many代表允许多个数据对象
ser_obj = UserInfoSerializers(instance=userInfo_objs, many=True)
print('ser_obj.data.type:', type(ser_obj.data))
# 3、返回给用户
context = {
'status': True,
'data': ser_obj.data
}
return Response(context)
使用postman发送GET请求进行测试
9.1.5通过序列化器的嵌套来处理m2m字段
python
#表结构:
class Auther(models.Model):
#著作表
name=models.CharField(verbose_name='作者',max_length=32)
class Book(models.Model):
#图书表
title=models.CharField(verbose_name='书名',max_length=128)
#auther为MToM类型,并关联到Auther
#一个著作可以有多本书
auther=models.ManyToManyField(verbose_name='作者',to=Auther,related_name='books')
python
#创建url
urlpatterns = [
path('api/<str:version>/auther/',views.AutherView.as_view(),name='auther'),
p
]
python
#图书序列化器
class BookSerializers(serializers.ModelSerializer):
#书系列化器
class Meta:
model = models.Book
fields = '__all__'
python
#著作序列化器
class AutherSerializers(serializers.ModelSerializer):
#著者系列化器
#books字段通过上面创建的图书序列化器来进行序列化
books=BookSerializers(many=True)
class Meta:
model = models.Auther
fields = ['name','books']
python
#视图类
class AutherView(APIView):
# 用户视图类
# 无需认证
authentication_classes = []
def get(self, request, *args, **kwargs):
# 1、获取数据库中的数据
# 多条数据
auther_objs = models.Auther.objects.all()
# 2、序列化器转换成JSON,many代表允许多个数据对象
ser_obj = AutherSerializers(instance=auther_objs, many=True)
# print('ser_obj.data.type:', type(ser_obj.data))
# 3、返回给用户
context = {
'status': True,
'data': ser_obj.data
}
return Response(context)
通过postman发送请求进行测试
9.1.6序列化器的继承
python
class BaseSerializers(serializers.Serializer):
#基础序列化器
#这里定义了一个xxx字段,数据来源是数据对象中的name属性
xxx=serializers.CharField(source='name')
class BookSerializers(serializers.ModelSerializer):
#书系列化器
class Meta:
model = models.Book
fields = '__all__'
class AutherSerializers(serializers.ModelSerializer,BaseSerializers):
#这个序列化器继承了BaseSerializers,所以也可以使用BaseSerializers中的xxx字段
#著者系列化器
books=BookSerializers(many=True)
class Meta:
model = models.Auther
fields = ['name','books','xxx']
9.2使用序列化器校验数据
9.2.1基本校验
python
#创建url
urlpatterns = [
path('login/', views.LoginView.as_view()),
]
python
#创建序列化器
class LoginSerializers(serializers.Serializer):
#required=True代表不允许为空,默认值就是True
name=serializers.CharField(required=True)
password=serializers.CharField(required=True)
python
#视图类
class LoginView(MyAPIView):
#用户登入,不需要认证
authentication_classes = []
def post(self,request):
#序列化用户传递过来的数据
ser_obj=LoginSerializers(data=request.data)
if ser_obj.is_valid():
#如果数据有效,则将有效的数据返回给用户
return Response(ser_obj.validated_data)
#如果数据无效,则返回错误信息
return Response(ser_obj.errors)
使用postman进行测试
9.2.2内置检验和正则表示式检验
python
#创建序列化器
from rest_framework import serializers
from django.core.validators import RegexValidator
class LoginSerializers(serializers.Serializer):
name=serializers.CharField(required=True)
#password字段最大长度为32,最小长度为8
password=serializers.CharField(required=True,max_length=32,min_length=8)
#order字段最大值为100,最小值为10
order=serializers.IntegerField(required=False,max_value=100,min_value=10)
#gender只允许为1或2
gender=serializers.ChoiceField(choices=((1,'男'),(2,'女')))
#EmailField必须输入Email格式的数据
email=serializers.EmailField(required=True)
#手机号字段使用正则表达式检验,必须满足正则表达式的规则才能通过校验
mobilePhone=serializers.CharField(validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$','手机号格式错误')])
使用postman进行测试
9.2.3钩子校验
python
#序列化器
from rest_framework import serializers
from rest_framework import exceptions
class LoginSerializers(serializers.Serializer):
name=serializers.CharField(required=True)
password=serializers.CharField(required=True,max_length=32,min_length=6)
def validate_name(self,value):
#对某个字段进行钩子检验
user_obj=models.User.objects.filter(name=value).first()
if not user_obj:
#如果用户名不存在,则抛出错误信息
raise exceptions.ValidationError("用户名不存在")
return value
def validate(self, attrs):
#全局中钩子检验
name=attrs.get('name')
password=attrs.get('password')
user_obj=models.User.objects.filter(name=name,password=password).first()
if not user_obj:
#如果密码错误不存在,则抛出错误信息
raise exceptions.ValidationError('密码错误')
return attrs
9.2.4ModelSerializer进行数据校验
python
#创建Model序列化器(用于数据校验)
class RegisterModelSerializers(serializers.ModelSerializer):
confirm_password=serializers.CharField(required=True)
class Meta:
model=models.User
fields=['name','password','confirm_password','depart']
extra_kwargs={
#为各个字段添加参数
'name': {'max_length':32,'min_length':2},
'password': {'validators':[RegexValidator(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$')]},
}
def validate_confirm_password(self, value):
#确认密码钩子校验
password=self.initial_data.get('password',None)
if password != value:
raise exceptions.ValidationError('两次输入密码不一致')
return value
python
#创建Model序列化器(用于序列化返回给用户的数据)
class UserSerializers(serializers.ModelSerializer):
#role是chioces字段,这里可以获取它的文本内容
role=serializers.CharField(source='get_role_display')
#depart是ForeignKey字段,这里可以获取它的文本内容
depart=serializers.CharField(source='depart.title')
class Meta:
model=models.User
fields=["name","role","depart"]
python
#视图类
class RegisterViews(APIView):
# 用户登入,不需要认证
authentication_classes = []
def post(self,request):
#通过序列化器校验用户传递过来的数据
ser_obj=RegisterModelSerializers(data=request.data)
#判断校验是否通过
if ser_obj.is_valid():
#如果校验通过,则删除数据库中不存在的字段,添加数据库中存在但用户未传递的字段
ser_obj.validated_data.pop("confirm_password")
instance=ser_obj.save(role=3)
#通过序列化器序列化存入数据库中的数据,并返回给用户
data = UserSerializers(instance=instance).data
return Response(data)
return Response(ser_obj.errors)
使用postman进行测试
9.2.5使用一个序列化器既做校验又做序列化
python
#创建序列化器
class RegisterModelSerializers(serializers.ModelSerializer):
#write_only=True代表只做校验,不做序列化
confirm_password=serializers.CharField(required=True,write_only=True)
#read_only=True代表只做序列化,不做校验
role_text = serializers.CharField(source='get_role_display',read_only=True)
depart_text=serializers.CharField(source='depart.title',read_only=True)
class Meta:
model=models.User
fields=['name','password','confirm_password','role_text','depart','depart_text']
extra_kwargs={
#为各个字段添加参数
'name': {'max_length':32,'min_length':2},
#write_only=True代表只做校验,不做序列化
'password': {"write_only":True,'validators':[RegexValidator(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$')]},
#write_only=True代表只做校验,不做序列化
'depart':{"write_only":True}
}
def validate_confirm_password(self, value):
#确认密码钩子校验
password=self.initial_data.get('password',None)
if password != value:
raise exceptions.ValidationError('两次输入密码不一致')
return value
python
#视图类
class RegisterViews(APIView):
# 用户登入,不需要认证
authentication_classes = []
def post(self,request):
ser_obj=RegisterModelSerializers(data=request.data)
if ser_obj.is_valid():
ser_obj.validated_data.pop("confirm_password")
ser_obj.save(role=3)
return Response(ser_obj.data)
return Response(ser_obj.errors)
使用postman测试