目录
一、自定义序列化过程(推导)
以用户get请求功能为例,
- orm操作数据库查询数据对象
- 序列化数据成可以返回给前台的数据(json模块支持的类型)
- 返回数据给前台
from rest_framework.views import APIView
from rest_framework.response import Response
from django.conf import settings
from . import models
# 一、自定义序列化过程
class UserV1APIView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
# 一、单查
if pk:
# 1. orm操作数据库查询数据对象
user_dic = models.User.objects.filter(is_delete=False, pk=pk).values('username', 'sex', 'img').first()
if not user_dic: # 判断用户是否存在
return Response({
'status': 1,
'msg': 'pk error',
}, status=400)
# 2. 序列化数据成可以返回给前台的数据(json模块支持的类型)
user_dic['img'] = '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('img'))
# 3. 返回数据给前台
return Response({
'status': 0,
'msg': 'ok',
'results': user_dic
})
else:
# 二、群查
# 1. orm操作数据库查询数据对象
user_query = models.User.objects.filter(is_delete=False).values('username', 'sex', 'img').all()
# 2. 序列化数据成可以返回给前台的数据(json模块支持的类型)
for user_dic in user_query:
user_dic['img'] = '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('img'))
user_list = list(user_query)
# 3. 返回数据给前台
return Response({
'status': 0,
'msg': 'ok',
'results': user_list
})
二、Serializer类:底层序列化(了解)
(一)视图类序列化过程
其实就是讲自定义序列化过程封装成了一个文件中的UserSerializer类
- 设置序列化字段,字段名要与处理model类的属性名对应
- model类中没有在UserSerializer类中声明的字段不会被序列化
- 自定义序列化字段:
- 字段类型为SerializerMethodField(),对应的值由自定义get_自定义字段名(self, model_obj) 方法提供
- 一般值都与参与序列化的mode_obj有关
# api/model.py文件
from django.db import models
class User(models.Model):
SEX_CHOICES = (
(0, '女'),
(1, '男'),
)
username = models.CharField(max_length=64, verbose_name='用户名', blank=True, unique=True)
password = models.CharField(max_length=64, verbose_name='密码')
sex = models.IntegerField(choices=SEX_CHOICES, default=0, verbose_name='性别')
img = models.ImageField(upload_to='img', default='img/default.png', verbose_name='头像')
# api/serializers.py文件(需要自己新建)
class UserSerializer(serializers.Serializer):
# 1. 序列化字段名要与modle中对应的字典名相同
username = serializers.CharField()
# 2. 自定义序列化字段(SerializerMethodField)
gender = serializers.SerializerMethodField()
# 3. get_自定义字段名(self, model_obj) 方法
def get_gender(self, obj): # obj为参与序列化的model对象
return obj.get_sex_display()
# 自定义序列化字段
icon = serializers.SerializerMethodField()
def get_icon(self, obj):
return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, obj.img)
- many=True:群查,传入的user_query含有多个user_obj
- many=False:单查,传入的为user_obj,默认为False
# views.py文件
from . import serializers
class UserV2APIView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk')
if pk:
user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
if not user_obj:
return Response({
'status': 1,
'msg': 'pk error',
}, status=400)
# 1. 将对象对外提供的字段,以及整个序列化过程封装,形成序列化类
user_ser = serializers.UserSerializer(user_obj, many=False) # many默认为False
return Response({
'status': 0,
'msg': 'ok',
'results': user_ser.data
})
else:
user_query = models.User.objects.filter(is_delete=False).all()
# 2. 将对象对外提供的字段,以及整个序列化过程封装,形成序列化类
user_ser = serializers.UserSerializer(user_query, many=True)
return Response({
'status': 0,
'msg': 'ok',
'results': user_ser.data
})
(二)视图类反序列化过程
- 反序列化的字段需要设置条件
- reuqired参数:
- 不设置时,必须参与反序列化
- False时,前端不提供,则为默认值,提供了则必须进行校验
- 自定义校验字段:与系统字段定义方法相同,不能参与入库操作,一般用于全局校验,需要在全局钩子中,将其取出
- 局部钩子
- 命名方法:
validate_校验的字段名(self, 字段值value)
- 校验规则:成功直接返回value,失败抛出校验失败信息
ValidationError('错误信息')
- 命名方法:
- 全局钩子
- 命名方法:
validate(self, 所有的校验数据attrs)
- 校验规则:成功直接返回attrs,失败抛出校验失败信息
ValidationError({'异常字段', '错误信息'})
- 命名方法:
- 重写create方法:返回入库成功的对象
- validated_data:校验后可以入库的数据
- 重写update方法:返回入库成功的对象
- instance:要被修改的对象
- validated_data:代表校验后用来修改instance的数据
# api/serializers.py文件(需要自己新建)
cla
class UserDeSerializer(serializers.Serializer):
# 1. 反序列化的字段需要设置条件
username = serializers.CharField(min_length=3, max_length=16, error_messages={
'min_length': '太短',
'max_length': '太长'
})
password = serializers.CharField(min_length=3, max_length=16)
# 2. required=False的字段,前台不提供,走默认值,提供就一定进行校验;不写该字段则采用默认值
sex = serializers.BooleanField(required=False)
# 3. 自定义校验字段:与系统字段定义方法相同,不能参与入库操作,一般用于全局校验,需要在全局钩子中,将其取出
re_password = serializers.CharField(min_length=3, max_length=16)
# 4. 局部钩子:
def validate_username(self, value): # 命名方法:validate_校验的字段名(self, 字段值value)
if 'g' in value.lower():
raise serializers.ValidationError('名字中不能有g') # 失败抛出校验失败信息ValidationError('错误信息')
return value #成功返回value
# 5. 全局钩子:
def validate(self, attrs): # 命名方法: validate(self, 所有的校验数据attrs)
password = attrs.get('password')
re_password = attrs.pop('re_password')
if password != re_password:
raise serializers.ValidationError({'re_password': '两次密码不一致'}) # `ValidationError({'异常字段', '错误信息'})`
return attrs # 成功直接返回attrs
# 6. 重写create方法
def create(self, validated_data): # validated_data:校验后可以入库的数据
return models.User.objects.create(**validated_data)
# 7. 重写update方法
def update(self, instance: models.User, validated_data): # instance:要被修改的对象
validated_data.pop('username') # 用户名不能被修改
models.User.objects.filter(pk=instance.id).update(**validated_data)
return instance
- 调用序列化类的save方法完成入库,Serializer没有提供create和update的实现体(因此需要重写)
- 入库得到的user对象需要重新序列化的数据返回给前端,不然密码数据也会传输给前端
# views.py文件
from . import serializers
class UserV2APIView(APIView):
def post(self, request, *args, **kwargs):
user_ser = serializers.UserDeSerializer(data=request.data)
if user_ser.is_valid():
user_obj = user_ser.save()
return Response({
'status': 0,
'msg': 'ok',
# 将入库得到的user对象重新序列化的数据返回给前台
'results': serializers.UserSerializer(user_obj).data
})
else:
return Response({
'status': 1,
'msg': user_ser.errors,
})
三、ModelSerializer类:模型序列化(核心)
- Meta类:序列化类继承ModelSerializer类,所以需要在配置类Meta中进行配置
- model属性:绑定序列化相关的model表
- fields属性:采用插拔式设置所有参与序列化和反序列化字段(通过反射)
- extra_kwargs属性:将系统字段划分为三种
- read_only为True,序列化,
- write_only为True,反序列化
- 不设置:序列化和反序列化都参与
- required:有默认值的字段为选填字段,为True时为必填字段
- 自定义序列化字段:默认就是read_only,且不能修改
- 第一种:在序列化类中用SerializerMethodField()来实现
- 第二种:在模型类中用@property来实现,可插拔
- 自定义反序列化字段(定义方法和Serializer类相同 )
- 规则只能在此声明中设置,或是在钩子中设置,在extra_kwargs中对其设置的无效
- 必须设置 write_only
- 局部钩子
- 命名方法:
validate_校验的字段名(self, 字段值value)
- 校验规则:成功直接返回value,失败抛出校验失败信息
ValidationError('错误信息')
- 命名方法:
- 全局钩子
- 命名方法:
validate(self, 所有的校验数据attrs)
- 校验规则:成功直接返回attrs,失败抛出校验失败信息
ValidationError({'异常字段', '错误信息'})
- 命名方法:
- create和update方法不需要再重写,ModelSerializer类已提供,且支持所有关系下的连表操作
class UserModelSerializer(serializers.ModelSerializer):
# 第一种自定义序列化字段:该字段必须在fields中设置
# gender = serializers.SerializerMethodField()
# def get_gender(self, obj):
# return obj.get_sex_display()
# 自定义反序列化字段同Serializer类,且规则只能在此声明中设置,或是在钩子中设置,
# 在extra_kwargs中对其设置的无效
# 注:自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)
class Meta:
model = models.User
# fields采用插拔式设置所有参与序列化与反序列化字段
fields = ('username', 'gender', 'icon', 'password', 'sex', 're_password')
extra_kwargs = {
'username': { # 系统字段不设置read_only和write_only,默认都参加
'min_length': 3,
'max_length': 10,
'error_messages': {
'min_length': '太短',
'max_length': '太长'
}
},
'gender': {
'read_only': True, # 自定义的序列化字段默认就是read_only,且不能修改,可以省略
},
'password': {
'write_only': True,
},
'sex': { # 有默认值的字段,为选填字段('required': True可以将其变为必填字段)
'write_only': True,
# 'required': True
}
}
# 局部全局钩子同Serializer类,是与 Meta 同缩进的
def validate_username(self, value):
if 'g' in value.lower():
raise serializers.ValidationError('名字中不能有g')
return value
def validate(self, attrs):
password = attrs.get('password')
re_password = attrs.pop('re_password')
if password != re_password:
raise serializers.ValidationError({'re_password': '两次密码不一致'})
return attrs
# create和update方法不需要再重写,ModelSerializer类已提供,且支持所有关系下的连表操作
四、sys模块之标准三流
输出流和错误流之间异步执行, 谁先抢占到cpu资源谁先打印
- 标准输出流:stdout.write, 控制台白色字体打印
- 标准输入流:stdin.readline, 获取键盘输入信息,包括换行符
- 标准错误流:stderr.write, 控制台红色字体打印
import sys
# 1. 标准输出流
sys.stdout.write('123\n') # == print
# 2. 标准输入流:获取键盘输入信息,包括换行符
res = sys.stdin.readline()
print(res)
# 3. 标准错误流:控制台红色字体打印
sys.stderr.write('xyz\n')