APIView+Response+序列化类、高级用法source、高级用法定制字段、多表关联序列化和反序列化、反序列化校验总结
函数和方法再回顾
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)) print(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+序列化类)
序列化器(序列化类)
# 序列化类 from rest_framework import serializers from rest_framework.exceptions import ValidationError from app01 import models class BookSerializer(serializers.Serializer): name = serializers.CharField(max_length=16, min_length=2) price = serializers.IntegerField() # publish = serializers.IntegerField(to='Publish', on_delete=True) # 局部钩子 def validate_name(self, value): if not value: raise ValidationError('名字不能为空') if value.startswith('sb'): raise ValidationError('名字不能以“sb”开头') return value # 全局钩子 def validate(self, attrs): # 前端传入的所有数据,校验过后attrs 字典 name = attrs.get('name') price = attrs.get('price') if name == price: raise ValidationError('名字和价格不能一样') else: return attrs # 重写create方法 def create(self, validated_data): book = models.Book.objects.create(**validated_data) return book # 重写update方法 def update(self, instance, validated_data): ''' instance:待修改对象 validated_data:校验后的数据 ''' # 方式一 # instance.name = validated_data.get('name') # instance.price = validated_data.get('price') # instance.save() # 方式二 反射:通过字符串动态的获取或设置属性或方法 # 循环出字典的key值 for k in validated_data: setattr(instance, k, validated_data.get(k)) # 每次循环都相当于instance.k = validated_data.get(k) instance.save() return instance
视图类
from rest_framework.views import APIView from app01 import serializer from rest_framework.response import Response from app01 import models # Create your views here. class BookView(APIView): # 查询所有信息 def get(self, request): all_data = models.Book.objects.all() # 序列化数据 ser = serializer.BookSerializer(instance=all_data, many=True) return Response(ser.data) # 添加信息 def post(self, request): # 反序列化前端传过来的数据 ser = serializer.BookSerializer(data=request.data) if ser.is_valid(): # 数据三层校验 ser.save() # 保存数据 return Response({'code': 100, 'msg': '添加成功'}) else: return Response({'code': 101, 'msg': ser.errors}) class BookDetailView(APIView): # 查询一条信息 def get(self, request, pk): one_data = models.Book.objects.all().filter(pk=pk).first() # 序列化数据 ser = serializer.BookSerializer(instance=one_data) return Response(ser.data) # 修改信息 def put(self, request, pk): # 先找到原信息 old_data = models.Book.objects.filter(pk=pk).first() # 序列化 ser = serializer.BookSerializer(instance=old_data, data=request.data) if ser.is_valid(): ser.save() return Response({'code': 100, 'msg': '修改成功'}) else: return Response({'code': 100, 'msg': ser.errors}) # 删除一条信息 def delete(self, request, pk): models.Book.objects.filter(pk=pk).delete() return Response({'code': 100, 'msg': '删除成功'})
高级用法source(了解)
# 字段类的属性 # 如下写法,就能修改序列化的字段 class BookSerializer(serializers.Serializer): # 用法一 # book_name = serializers.CharField(max_length=16, min_length=2, source='name') # 前端显示:"book_name": "金刚经" name = serializers.CharField(max_length=16, min_length=2, ) # 用法一:跨表查询 自动对应成出版社的名字 publish = serializers.CharField(source='publish.name') # "publish": "五台山出版社" # 用法一:需要在models文件中class类下写一个get_name方法 xxx = serializers.CharField(max_length=16, min_length=2, source='get_name') # "xxx": "金刚经-佛" price = serializers.IntegerField() # 前端看到 [ { "name": "金刚经", "publish": "五台山出版社", "xxx": "金刚经-佛", "price": 111 } ]
高级用法定制字段
class BookSerializer(serializers.Serializer): # 用法一 # book_name = serializers.CharField(max_length=16, min_length=2, source='name') # 前端显示:"book_name": "金刚经" name = serializers.CharField(max_length=16, min_length=2, ) # 用法一:跨表查询 自动对应成出版社的名字 publish = serializers.CharField(source='publish.name') # "publish": "五台山出版社" # 用法一:需要在models文件中class类下写一个get_name方法 xxx = serializers.CharField(max_length=16, min_length=2, source='get_name') # "xxx": "金刚经-佛" price = serializers.IntegerField() # 方式一:使用SerializerMethodField 定制 publish_detail = serializers.SerializerMethodField() def get_publish_detail(self, obj): # 返回什么,序列化后publish就是什么 return {'name': obj.publish.name, 'addr': obj.publish.addr} # 方式二: 在models表中写一个publish_dic同名方法,返回什么前端就显示什么 publish_dic = serializers.DictField() ''' models中的 @property def publish_dic(self): return {'name': self.publish.name, 'addr': self.publish.addr} '''
多表关联序列化和反序列化
# 以后一个序列化类,想即做序列化,又做反序列化,会出现问题:字段不匹配,尤其是多表关联的字段 # 以后,有的字段 即做序列化,又做反序列化 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":"111111","price":999,"publish":1,"authors":[1,2]} authors=validated_data.pop('authors') book = Book.objects.create(**validated_data) # 增加中间表的记录:图书和作者的关系 book.authors.add(*authors) # 向中间表中存入:这个图书关联的做作者 return book
反序列化校验总结
# 什么情况用反序列化校验? 做反序列化的时候,才用----》校验前端传入的数据 # 三层: 字段自己:字段类属性---》可控制的比较小 局部钩子:单个字段校验 全局钩子:多个字段同时校验