目录
DRF序列化组件是drf提供的一个类, rest_framework.serializers.Serializer, 我们可以继承它来写自己的类.
序列化器Serializer
作用:
1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能
序列化组件基本使用
开一个py文件serializer,定义一个序列化类
from rest_framework import serializers
# 写序列化类. 给book序列化
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
price = serializers.CharField()
publish = serializers.CharField()
使用序列化类, 序列化多条数据
class BookView(APIView):
def get(self,request):
book_list = Book.objects.all()
ser = BookSerializer(instance=book_list,many=True)
return Response(ser.data)
instance 表示要序列化的数据, many=True表示序列化多条, instance是queryset对象, 一定要传many=True
使用序列化类,序列化单条数据
class BookDetailView(APIView):
def get(self,request,pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
反序列化(新增, 修改)
新增
视图类
# 反序列化, 新增
class BookView(APIView): # APIView继承自django的View
def get(self,request):
book_list = Book.objects.all()
ser = BookSerializer(instance=book_list,many=True)
return Response(ser.data)
def post(self,request):
# 前端传递数据, 从request.data取出来
ser = BookSerializer(data=request.data)
if ser.is_valid(): # 表示校验前端传入的数据, 没有写校验规则, 现在等于没有校验
ser.save() # 在写东西这里就会报错, 调用save方法, 判断 如果instance有值执行update, 没有值就执行create
return Response(ser.data)
else:
return Response(ser.errors)
序列化类
def create(self,validated_data):
res = Book.objects.create(**validated_data)
return res
视图类
# 修改
class BookDetailView(APIView):
def get(self,request,pk):
book = Book.objects.filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
def put(self,request,pk):
book = Book.objects.filter(pk=pk).first()
# 前端传递数据, corequest.data取出来
ser = BookSerializer(instance=book,data=request.data)
if ser.is_valid(): # 表示校验前端传入的数据, 没有写校验规则就等于没校验
ser.save() # 在写东西就会报错, 调用save会触发BookSerizlizer的save方法, 判断, 如果instance有值执行update, 没有执行create
return Response(ser.data)
else:
return Response(ser.errors)
序列化类
def update(self,instance,validated_data):
# instance要修改的对象
# validated_data校验过后的数据
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.publish = validated_data.get('publish')
instance.save()
return instance
序列化类的常见字段类和常见参数
常用字段类型
字段 | 字段构造方式 |
---|---|
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=) |
选项参数
参数名称 | 作用 |
---|---|
max_length | 最大长度 |
min_lenght | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最小值 |
min_value | 最大值 |
通用参数
参数名称 | 说明 |
---|---|
read_only | 表明该字段仅用于序列化输出,默认False |
write_only | 表明该字段仅用于反序列化输入,默认False |
required | 表明该字段在反序列化时必须输入,默认True |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 该字段使用的验证器 |
error_messages | 包含错误编号与错误信息的字典 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
常用的字段类型
CharField
BooleanField
IntegerField
DecimalField# 这两个是序列化列独有的
ListField: {name:'lqz',age:19,hobby:['篮球','足球']} # 可以以列表存储
DictField:{name:'lqz',age:19,wife:{'name':'jason','age':18}} # 可以以字典存储
常用字段参数
# 给CharField字段使用的参数
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符# 给IntegerField字段类使用的参数
min_value 最小值
max_value 最大值
补充
read_only 表明该字段只能用于序列化输出给前端或其他
write_only 表明该字段只能用于反序列化输入
序列化类之source
该参数主要用于修改序列化字段的名字
# 现在我们编写了一个book表:
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.CharField(max_length=32)
# 然后我们编写一个获取图书的接口 需要用到序列化类
class BookSerializer(serializers.Serializer):
name = serializers.CharField(min_length=3, max_length=8)
price = serializers.CharField(min_length=3, max_length=8)
publish = serializers.CharField(min_length=3, max_length=8)
# 我们在使用序列化类 然后把书籍传到前端显示 接口
class BookView(APIView):
def get(self, request):
book_list = Book.objects.all()
ser = BookSerializer(instance=book_list, many=True)
return Response(ser.data)
序列化的字段名称是什么,前端就会返回什么
如果想要在前端的name字段显示book_name, 我们就可以使用source参数
book_name = serializers.CharField(min_length=3, max_length=8, source='name') # 字段名称写自己想要的 source后面跟上表的字段名称
定制序列化类的两种方式
在序列号类中写SerializerMethodField
xxx = serializers.SerializerMethodField()
# obj是当前序列化类的对象
def get_xxx(self, obj):
return {'name': obj.name}
# 获取书籍对象的所有作者
author = serializers.SerializerMethodField()
def get_author(self, book_obj):
return [{'name': obj.name, 'age': obj.age, 'phone': obj.author_detail.phone} for obj in book_obj.author.all()]
在模型类中定义方法
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6, decimal_places=2)
create_time = models.DateField()
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
author = models.ManyToManyField(to='Author')
def __str__(self):
return f'{self.name}'
# 可以加property装饰 也可以不加 序列化组件可以不用加括号拿到
@property
def publish_detail(self):
return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}
def author_list(self):
return [{'name': obj.name, 'age': obj.age, 'phone': obj.author_detail.phone} for obj in self.author.all()]
有关联关系表数据创建
# 只写不读 只反序列化不序列化
publish = serializers.IntegerField(write_only=True)
author = serializers.ListField(write_only=True)
# 只读不写 只序列化不反向序列化
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
# 继承serializers.Serializer一定要重写creata方法和update方法
def create(self, validated_data):
name = validated_data.get('name')
price = validated_data.get('price')
create_time = validated_data.get('create_time')
publish = validated_data.get('publish')
author = validated_data.get('author')
# 创建书籍数据
obj = Book.objects.create(name=name, price=price, create_time=create_time, publish_id=publish)
# 添加书籍和作者关系 多对多
obj.author.add(*author)
return obj
def update(self, instance, validated_data):
name = validated_data.get('name')
price = validated_data.get('price')
create_time = validated_data.get('create_time')
publish = validated_data.get('publish')
author = validated_data.get('author')
instance.name = name
instance.price = price
instance.create_time = create_time
instance.publish_id = publish
instance.author.set(author)
instance.save()
return instance
总结:继承Serializer的序列化组件需要写校验的每个字段,创建和修改数据时,需要重写create和update方法。而使用ModelSerializer,不需要写这些。
反序列化之数据校验
首先是校验字段自己的校验规则 , 通过后校验局部钩子,最后校验全局钩子
字段自己的校验规则
class BookSerializer(serializers.Serializer):
# 继承Serializer字段自己的校验规则
book_name = serializers.CharField(max_length=8, min_length=3, required=True,)
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['name', 'price', 'create_time', 'publish', 'author', 'publish_detail', 'author_list']
extra_kwargs = {
#继承ModelSerializer字段自己的校验规则
'name': {'max_length': 8, 'min_length': 3},
}
局部钩子
def validate_name(self, name):
if 'sb' in name:
raise ValidationError('名字不能包含敏感词')
return name
def validate_price(self, price):
if price == 66:
raise ValidationError('价格不能是66')
return price
全局钩子
def validate(self,attrs):
if attrs.get('password') != attrs.get('re_password'):
raise ValidationError('两次密码不一致')
return attrs
模型类序列化器[ModelSerializer]的使用
1. 定义一个序列化组件类, 继承ModelSerializer.
2. 在序列化组件类中定义有个Meta类, 类中指定model和fields参数
3.在Meta类中指定extra_kwargs,给字段添加参数
4. 在序列化类中, 可以重写某个字段, 优先使用你重写的
5. 不需要再重写create 和 update方法
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = Book
# fields = ['__all__'] 所有字段都序列化
fields = ['name', 'price', 'create_time', 'publish', 'author', 'publish_detail', 'author_list']
extra_kwargs = {
'name': {'max_length': 8, 'min_length': 3},
'price': {'min_value': 9, 'max_value': 199},
'publish': {'write_only': True},
'author': {'write_only': True},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
}
def validate_name(self, name):
if 'sb' in name:
raise ValidationError('名字不能包含敏感词')
return name
def validate_price(self, price):
if price == 66:
raise ValidationError('价格不能是66')
return price
反序列化数据校验源码分析
入口时序列化组件对象>> is_valid()方法
BaseSerializer里的is_valid
def is_valid(self, *, raise_exception=False):
if not hasattr(self, '_validated_data'):
try:
# 真正开始校验 如果校验成功返回校验通过的数据
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
执行self.run_validation(self.initial_data)
Serializer里的run_validation
def run_validation(self, data=empty):
# 执行局部钩子
value = self.to_internal_value(data)
try:
# 执行全局钩子
self.run_validators(value)
value = self.validate(value)
assert value is not None, '.validate() should return the validated data'
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
def to_internal_value(self, data):=
for field in fields:
# 反射判断是否有局部钩子函数
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
# 字段本身的校验规则
validated_value = field.run_validation(primitive_value)
# 局部钩子校验
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret