APIView+Response+序列化类、高级用法source、高级用法定制字段、多表关联序列化和反序列化、反序列化校验总结

发布时间 2023-08-31 22:29:11作者: 吼尼尼痛

函数和方法再回顾

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

反序列化校验总结

# 什么情况用反序列化校验?    
    做反序列化的时候,才用----》校验前端传入的数据
    
    
# 三层:
    字段自己:字段类属性---》可控制的比较小
    局部钩子:单个字段校验
    全局钩子:多个字段同时校验