7.10.serializer和validator验证
serializers
作用
控制返回体中包括哪些字段
检验请求体中字段的有效性,当校验失败时返回错误信息
数据格式转换
序列化:允许将复杂对象序列化为易于渲染成JSON、XML的原生python数据类型
反序列化:在数据校验通过后,将json、xml等数据反序列化为复杂对象
类型
serializers
控制返回体中包括哪些字段
class GoodsCategorySerializer(serializers.Serializer):
name = serializers.CharField()
code = serializers.CharField()
desc = serializers.CharField()
category_type = serializers.IntegerField()
检验请求体中字段的有效性,当校验失败时返回错误信息
自定义创建和更新逻辑
from rest_framework import serializers
from goods.models import Goods
from trade.models import ShoppingCart
class ShopCartSerializer(serializers.Serializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
nums = serializers.IntegerField(required=True, min_value=1,
error_messages={
'min_value': '商品数量不能小于1',
'required': '请选择购买数量'
}
)
goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())
# 自定义创建逻辑
def create(self, validated_data):
# 获取用户信息
user = self.context['request'].user
nums = validated_data['nums']
goods = validated_data['goods']
existed = ShoppingCart.objects.filter(user=user, goods=goods)
if existed:
existed = existed[0]
existed.nums += nums
existed.save()
else:
existed = ShoppingCart.objects.create(**validated_data)
return existed
# 自定义更新逻辑
def update(self, instance, validated_data):
instance.nums = validated_data['nums']
instance.save()
return instance
modelSerializer
ModelSerializer简化了Serializer的使用,但存在一定的局限性。比如Model中要求必须存在的字段而Form中没有;再比如Form中需要校验的字段而Model中没有
控制返回体中包括哪些字段
goods/serializer.py
class GoodsCategorySerializer(serializers.ModelSerializer):
class Meta:
model = GoodsCategory
fields = ('name', 'code', 'desc', 'add_time')
若需要取出所有字段使用
fields = '__all__'
检验请求体字段,当校验失败时返回错误信息
详见:《validator校验器》小节
常见问题
GET请求:如何向response中添加model中没有的数据?
POST请求:如何向表单中添加额外的数据?
同Serializer,使用code = serializers.CharField()
的方式声明额外数据, 并向fields中添加
示例:User中没有code字段,向注册表单中添加code字段的方法如下:
class UserRegSerializer(serializers.ModelSerializer):
code = serializers.CharField(...)
def validate(self, attrs):
...
# 若提交的数据中存在不属于Model中的数据,将会报错
# UserProfile() got an unexpected keyword argument 'code'
# 解决方式:重写validate方法,通过del attrs["code"] 删除额外的数据
del attrs["code"]
return attrs
class Meta:
model = User
fields = ('username', 'code', 'mobile', 'password')
POST请求:某些字段表单中存在,但表单存储后不想返回怎么办?
使用write_only=True声明该字段仅允许被写入,如下:
password = serializers.CharField(style={'input_type': 'password'}, help_text="密码", label="密码", write_only=True)
完整示例
class UserRegSerializer(serializers.ModelSerializer):
code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label="验证码",error_messages={
"blank": "请输入验证码",
"required": "请输入验证码",
"max_length": "验证码格式错误",
"min_length": "验证码格式错误"
},
help_text='验证码')
def validate(self, attrs):
attrs["mobile"] = attrs["username"]
attrs["password"] = make_password(attrs["password"])
del attrs["code"]
return attrs
class Meta:
model = User
fields = ('username', 'code', 'mobile', 'password')
validator校验器
校验规则可能来自model或serializer
class UserRegSerializer(serializers.ModelSerializer):
# 使用系统自带校验器
code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label="验证码",
error_messages={ # 校验失败错误信息
"blank": "请输入验证码",
"required": "请输入验证码",
"max_length": "验证码格式错误",
"min_length": "验证码格式错误"
},
help_text='验证码')
username = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False,
validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")])
password = serializers.CharField(style={'input_type': 'password'}, help_text="密码", label="密码", write_only=True)
# 对单一字段进行自定义校验
def validate_code(self, code):
verify_records = VerifyCode.objects.filter(mobile=self.initial_data["username"]).order_by("-add_time")
if verify_records:
last_record = verify_records[0]
five_minutes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
if five_minutes_ago > last_record.add_time:
raise serializers.ValidationError("验证码过期") # 自定义校验错误信息
if last_record.code != code:
raise serializers.ValidationError("验证码错误")
else:
raise serializers.ValidationError("验证码错误")
# 对所有字段进行校验
def validate(self, attrs):
attrs["mobile"] = attrs["username"]
# attrs["password"] = make_password(attrs["password"]) # 对密码加密,方式一
del attrs["code"]
return attrs
def create(self, validated_data):
# 对密码加密,方式一
user = super(UserRegSerializer, self).create(validated_data=validated_data)
user.set_password(validated_data["password"])
user.save()
return user
class Meta:
model = User
fields = ('username', 'code', 'mobile', 'password')
Last updated
Was this helpful?