|
# Serializer类,如何序列化
1、需要序列化什么,必须写一个类继承serializer.Serializer
2、像序列化什么字段,就在类里面写什么字段,一般情况下序列化的字段和models都是一样的,但是想写不一样的就可以通过source='字段名'来控制
[source的3个作用(很多字段类)]
修改字段名
隐藏的book.方法,eg:source="publish.email" ==> book.publish.email
执行类的方法 类的绑定方法
3、序列化queryset(列表也可以,因为queryset继承了列表)和真正的对象
1、序列化得到一个字段,序列化对象.data
book_ser=BookSerializer(对象)
Response(book_ser.data)
2、自己封装Response方法
class MyResponse():
def __init__(self):
self.status=100
self.msg='成功'
@property
def get_dict(self):
return self.__dict__
if __name__ == "__main__"
res=MyResponse()
res.data={'name':'lqz'} #对象给他的data属性加值,会自动保存到__init__里面去,在后面导入这个模块就可以了,然后需要该值就生成对象,res=MyResponse(),res.status=102就可以了
res.get_dict
print()
4、反序列化 view中的put方法 book_ser=BookSerializer(instance=要序列化的对象,data= request.data)
[5、字段验证顺序:]
1、序列化类中,给字段加属性,
2、局部和全局钩子函数,
3、写一个函数,在Serializer字段中加入validators=[函数地址]
4、调用is_valid()就会走验证,先走字段验证完,在走局部钩子,循环结束完,最后再走全局钩子,所以可以总结出来,在全局的Validate数据是符合上面的规则的数据
5、*了解*:is_valid(),里面加入raise_exception=True只要验证不通过就直接抛异常,不会去捕获了
6、修改保存---》调用序列化对象.save(),但是要重写Serializer类的update方法,有一个一个字段去核对
def update(self, instance, validated_data):
# instance是book的这个对象
# validated_data是校验后的数据
instance.name=validated_data.get('name')
instance.price=validated_data.get('price')
instance.author=validated_data.get('author')
instance.publish=validated_data.get('publish')
instance.save() # instance这个是book对象=orm提供的save()
return instance # 后续可能需要用到所以返回回去
[*补充说明*]
如果前端传过来的数据的字段不是在同一张表,那么我们需要通过instance.字段把对象取出来,然后进行orm的保存操作create
7、反序列化的新增
1、和反序列化新增的差别就在与没有instance这个修改对象
2、book_ser=BookSerializer(data= request.data),通过源码可以看到一定要写data=request.data要不然会把这个传给了instance了
[3、源码可知,当序列化对象(book_ser).save()时候:
[1、当同时在字段中有instance和data的时候会自动调用update方法,-
[2、只有data的时候会调用create方法]
重写create可以很复杂
# ser.py 序列化类重写create方法
def create(self, validated_data):# 传统意义需要一个一个关键字传入,但是现在**打散会更加合适
instance = Book.objects.create(**validated_data)
return instance
*补充*
[validated_data中如如果有一些数据是不必要的,可以通过.pop('key')删除]
8、ModelSerializer 跟模型做对应
1、基本用法
class BookModelSerializer(serializers.ModelSerializer):
def validate_price(self, data):
pass
publish=serializers.CharField(source='publish.name')
[class Meta:
model=Book # 对应上models.py中的模型]
fields='__all__' [序列化全部字段]
# fields=('name','price','id','author','publish') # 只序列化指定的字段
# exclude=('name',) #跟fields不能都写,写谁,就表示排除谁
# read_only_fields=('price',)
# write_only_fields=('id',) #弃用了,使用extra_kwargs
extra_kwargs = { # 类似于这种形式name=serializers.CharField(max_length=16,min_length=4)
'price': {'write_only': True,max_length:16,min_length:4},
}
[1、字段自己的校验]
直接通过extra_kwargs传过去 :
[类似于这种形式name=serializers.CharField(max_length=16,min_length=4)==>'price': {'write_only': True,max_length:16,min_length:4}]
,相当于在之前Serializer中字段里面写了各种条件
[2、在类中写钩子函数]
跟之前一模一样,在class这个类下面写局部钩子
def validate_price(self, data): # validate_字段名 接收一个参数
# 如果价格小于10,就校验不通过
# print(type(data))
# print(data)
if float(data) > 10:
return data
else:
# 校验失败,抛异常
raise ValidationError('价格太低')
# 全局钩子
def validate(self, validate_data): # 全局钩子
print(validate_data)
author = validate_data.get('author')
publish = validate_data.get('publish')
if author == publish:
raise ValidationError('作者名字跟出版社一样')
else:
return validate_data
[3、如何通过对对象拿到对象的属性]
fields=('name','price','id','author','publish')
publish = serializer.Serializer(source="publish.name") 在ModelSerializer中自动会有class Meta:model=Book中的book对象,只是隐藏了
这样就可以把publish覆盖了
[4、自定义create和update方法]
def create():
pass
def update():
pass
自己写完会优先用自己的方法
13、many源码,many=True能够序列化多条数据的原因
[序列化多条,需要传many=True]
book_ser=BookModelSerializer(books,many=True)
book_one_ser=BookModelSerializer(book)
print(type(book_ser))
#<class 'rest_framework.serializers.ListSerializer'> 这里面列表中对应的都是modelSerializer的对象
print(type(book_one_ser))
#<class 'app01.ser.BookModelSerializer'>
[核心思想]
# 对象的生成--》先调用类的__new__方法,生成空对象
# 对象=类名(name=lqz),触发类的__init__()
def __new__(cls, *args, **kwargs):
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
# 没有传many=True,走下面,正常的对象实例化
return super().__new__(cls, *args, **kwargs)
[补充魔法方法]
# 类的__new__方法控制对象的生成
# __str__ 当对象被打印的时候触发这个方法、
# __dict__ 类来调用会把类的属性组合成字典,对象.__dict__会把对象的属性组成字典
# __call__ 对象被调用会触发
# __getattr__ 独享点属性时候会被触发这个方法
14、接口:统一子类的行为(其他语言)
python中推崇鸭子类型,子类写了该方法,就不用父类的了,但是接口的概念也是很有必要的统一规范如何实现:
1、abc模块控制
2、raise抛异常控制
|
|