drf-day4
昨日回顾
1、cbv源码分析
路由匹配成功》》》配置再路由上的第二个参数:执行了as_view的内存地址(request)》》》执行父类闭包函数view(request)》》》执行self.dispatch》》》视图类中的类没有》》》在父类找到执行》》》通过反射找到与请求方式方通的的方法》》》执行此方法,传入request.
2、apiview执行流程
路由匹配成功》》》》BookView.as_view()》》》APIView的as_view配置在路由上的第二个参:执行函数内存地址(request)》》》执行View的view(request)》》》但是它去除了csrf认证》》》dispatch》》》APIView的dispatch---》
1. 包装了新的request---》视图类的方法中的request是新的
2. 执行三大认证
3 .处理了全局异常
3、新的request
1. request.data 方法被包装成了数据属性
2. 地址栏中的参数 请求参数 request.query_params 本质就是request._request.GET
3 .用其他的跟之前一模一样
request.method》》》request._request.method
4、序列化组件
drf提供的一个可以做序列化和反序列化的类
作用:序列化、反序列化、数据校验
6、如何做序列化
1.创建一个serializer.py文件,写一个类继承serialzers.Serializer
2.写序列化字段,字段参数
3.在视图中:ser=BookSerializer(instance=序列化的对象,many=True)
4.ser.data
7、反序列化校验
ser=BookSerializer(data=request.data) if ser.is_valid:三层校验:字段自己,局部钩子,全局钩子 ser.errors:返回错误信息
8、反序列化保存
ser.save():需要配合序列化类中的重写create类来使用
函数与方法
from types import MethodType, FunctionType # 一切皆对象,函数也是个对象, 由某个类产生 FunctionType def add(): pass print(isinstance(add, FunctionType)) # 判断一个对象是不是这个类的对象 print(isinstance(add, MethodType)) # 判断一个对象是不是这个类的对象 class Foo: def run(self): pass @classmethod def xx(cls): pass @staticmethod def zz(): pass # 对象调用 run ,run就是方法 会自动传值 f=Foo() print(isinstance(f.run,FunctionType)) prnt(isinstance(f.run,MethodType)) # 类来调用run,run就是函数,有几个值就要传几个值 print(isinstance(Foo.run,FunctionType)) print(isinstance(Foo.run,MethodType)) # 类调用类的绑定方法---》就是方法 print(isinstance(Foo.xx,FunctionType)) print(isinstance(Foo.xx,MethodType)) # 对象调用类的绑定方法---》 也是方法 print(isinstance(f.xx,FunctionType)) print(isinstance(f.xx,MethodType)) # 对象来调用 print(isinstance(f.zz,FunctionType)) # True print(isinstance(f.zz,MethodType)) #False # 类来调用 print(isinstance(Foo.zz,FunctionType)) # True print(isinstance(Foo.zz,MethodType)) #False
5个接口(apiview+response+序列化类)
1.接口代码
2.总结
1.序列化类》》》做序列化 多条一定要写,many=Ture 2.序列化校验 ser.is_valid() 就会走校验 3.反序列化保存 新增: ser = BookSerializer(data=request.data) ser.save()触发序列化类中的create方法,判断instance是否有值 create中,自己写保存到哪个表中:有数据》》》保存到某个表中 修改: ser = BookSerializer(instance=待修改对象,data=request.data) ser.save()》》》触发 序列化类中的 update》》》为什么?内部做了判断:根据是否有instance update中,有待修改对象,有数据---》修改完保存即可--》两种方式
反序列化之更新
视图类
class BookDetailView(APIView): def put(self, request, pk, *args, **kwargs): # 要用查出来的对象,使用传入的数据,做修改 book=Book.objects.filter(pk=pk).first() ser = BookSerializer(instance=book,data=request.data) # 使用前端传入的数据,修改book if ser.is_valid(): ser.save() # 调用了序列化类的save:内部会触发序列化类中 update方法的执行 不是book.save() return Response({'code': 100, 'msg': '修改成功'}) else: return Response({'code': 100, 'msg': ser.errors})
序列化类
class BookSerializer(serializers.Serializer): name = serializers.CharField() price = serializers.IntegerField() publish = serializers.CharField() # 重写create 前端传入,校验过后的数据validated_data def create(self, validated_data): book = Book.objects.create(**validated_data) # 前端传入的key值必须跟数据库字段一致的 return book # 如果是修改,需要重写update方法 def update(self, instance, validated_data): # instance 就是pk 2 # Book.objects.filter(pk=instance).update(**validated_data) # instance 待修改的对象 咱们在 view中的那个book # validated_data 校验过后的数据 本质还是 request.data 经过了数据校验 # 方式一: # instance.name=validated_data.get('name') # instance.price=validated_data.get('price') # instance.publish=validated_data.get('publish') # instance.save() # 方式二: 反射是通过字符串动态的获取或设置属性或方法 # get=getattr(self,'get') # get() # setattr(instance,'name','西游记') ---》 instance.name='西游记' for k in validated_data: # {"name":"西游记","price":99,"publish":南京出版社} setattr(instance, k, validated_data.get(k)) # instance.publish=validated_data.get('publish') instance.save() return instance
高级用法source
用法1:在序列化类中拿到表中字段
xxx = serializers.CharField(source='name')
用法3:表模型中写方法,拿到方法的返回值
表模型:
@property
def get_name(self):
return self.name+'sb'
序列化类:yyy = serializers.CharField(source='get_name')
前端:"yyy": "三毛流浪记sb"
高级用法定制字段
定制返回字段的格式,publish也是一个对象
{"name": "信息","price": 12,"publish": {name:xx,addr:xx}}
方案一:使用SerializerMethodField 定制
在序列化类中使用SerializerMethodField publish_detail = serializers.SerializerMethodField() def get_publish_detail(self, obj): # 返回什么,序列化后publish就是什么 # obj 就是序列化到的book对象 return {'name':obj.publish.name,'addr':obj.publish.addr}
方案er: 在表模型中定制
1 表模型中写方法,包装成数据属性
@property def publish_dict(self): return {'name': self.publish.name}
2 序列化类中
publish_dict=serializers.DictField()
多表关联序列化和反序列化
以后一个序列化类,想即做序列化,又做反序列化,会出现问题:字段不匹配,尤其是多表关联的字段
有的字段 即做序列化,又做反序列化
name = serializers.CharField()
price = serializers.IntegerField()
有的字段:只做序列化(read_only表示 只做序列化)
publish_dict = serializers.DictField(read_only=True) # 只做序列化 author_list = serializers.ListField(read_only=True) # 只做序列化
有的字段只做反序列化(write_only=True)》》》是什么类型,取决于前端传入的格式什么样
publish_id = serializers.IntegerField(write_only=True) # 反序列化 authors = serializers.ListField(write_only=True) # 反序列化
保存方法需要自己重写
def create(self, validated_data): # {"name":"三国演义","price":999,"publish":1,"authors":[1,2]} authors=validated_data.pop('authors') book = Book.objects.create(**validated_data) # 增加中间表的记录:图书和作者的关系 book.authors.add(*authors) # 向中间表中存入:这个图书关联的做作者 return book
笨办法:
序列化用一个序列化类
反序列化换另一个序列化类
反序列化校验总结
什么情况用反序列化校验
做反序列化的时候,才用》》》校验前端传入的数据
三层:
字段自己:字段类属性---》可控制的比较小
局部钩子:单个字段校验
全局钩子:多个字段同时校验
拓展:
新增传这种数据过来,新增图书,新增一个作者,新增一个出版社
{"name":"新西游记111","price":199,"publish_id":{name:西安出版社,addr:西安},"authors":[{"name": "lqz","sex": "男","age": 19}]}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY