序列化器的介绍和快速使用

drf提供了两个类:Serializer和ModelSerializer
    之后我们只需要写自己的类,继承drf提供的序列化类,使用其中的方法就行
之后接口的编写我们可以使用APIView+序列化类+Response来完成

序列化类的基本使用--序列化多条

serializer.py--BookSerializer类(序列化类)

from rest_framework import serializers
class BookSerializer(serialiaer.Serializer):
    name = serializers.CharField()  # 大致与models下的类是对应的
    price = serializers.CharField()

views.py--BookView类(视图类)

class BookView(APIView):
    def get(self, request):
        books = models.Book.objects.all()
        # instance要序列化的数据,many=True则是用于queryset对象,如果是单个对象则不用传
        ser = BookSerializer(instance=books, many=True)
        # 无论是列表还是字典都可以被序列化
        return Response(ser.data)

序列化单条数据

序列化类不动,视图类有改动

class BookDetailView(APIView):
    def get(self, request, *args, **kwargs):
        # 为了防止有多个参数使用可变长参数,所需参数从可变长参数中提取
        book = models.Book.objects.filter(pk=kwargs.get('pk')).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)

反序列化

序列化类

1.新增
    在序列化类中添加即可
    def create(self, validated_data):
        book = models.Book.objects.create(**validated_data)
        return book
    
2.修改
    def undate(self, instance, validated_data):
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.save() 
        return instance

视图类

1.新增
    class BookView(APIView):
        def post(self, request):
            ser = BookSerializer(data=request.data)  # 将前端传入的数据给data参数
            # 校验数据
            if ser.is_valid():
                ser.save()
                return Response({'code': 100, 'msg': '新增成功', 'result': ser.data})
            else:
                return Response({'code': 101, 'msg': ser.errors})
            
2.修改
    class BookDetailView(APIView):
        def put(self, request, pk):
            book = Book.objects.filter(pk=pk).first()
            ser = BookSerializer(data=request.data, instance=book)
            if ser.is_vaild():
                ser.save()
                return Response({'code':100, 'msg': '修改成功', 'result': ser.data})
            else:
                return Response({'code': 101, 'msg': ser.errors})

反序列化的校验

在序列化类中添加钩子函数即可
1.局部钩子
    def vaildata_name(self, name):
        if 判断条件:
            raise ValidationError('异常提示')  # 校验不通过,抛异常
        else:
            return name
            
2.全局钩子
    def validate(self, attrs):
        if 判断条件:
            raise ValidationError('异常提示')
        else:
            return attrs

序列化类常用字段和字段参数

常用字段

'''重要'''
1.CharField  # 字符
2.IntegerField  # 数字,整数
3.DecimalField  # 数字,小数
4.DateTimeField  # 时间,年月日时分秒
5.BooleanDield  # 布尔值
6.ListField  # 存列表
7.DictField  # 存字典
8.SerializerMethodField  # 用于定义数据的返回格式

'''了解'''
2.EmailField  # 邮件
3.RegexField  # 正则
5.URLField  # 存URL
6.UUIDField  # 存xxx-xxx-xxx格式数据
7.IPAddressField  # 存IP地址
8.FloatField  #  
9.DurationField  # 存时间戳
10.ChoiceField  # 与django 中的choice相同
11.MultipleChoiceField  # 多选
12.FileField  # 文件
13.ImageField  # 图片

常用段参数

1.CharField及其子类中使用的
    max_length       最大长度
    min_length       最小长度
    allow_blank      是否允许为空
    trim_whitespace  是否截断空白字符
    
2.IntegerField中使用的
    max_value  最大值
    min_value  最小值
    
3.所有字段类都有的
    read_only  表明该字段仅用于序列化输出,默认False(重点)
    write_only  表明该字段仅用于反序列化输入,默认False(重点)
    required  表明该字段在反序列化时必须输入,默认为True
    default   反序列化时使用的默认值
    allow_null  表明该字段是否允许传入None,默认为False
    validators  该字段使用的验证器

序列化高级用法之source

source也是一个字段参数,它的作用是修改传给前台的字段名,但是数据库中的字段名不变,即它可以定制字段名字
用法:用在序列化类中的
    自有字段
        real_name = serializer.CharField(max_length=8, source='name')
        # 通过source关联数据库中的name字段,该字段的数据在前台展示时显示的字段名为real_name
    关联字段,一对多,通过关联的表名点字段名
        publish_name = serializer.CharField(source='publish.name')
        # publish表中name字段的数据展示给前台显示的字段名为publish_name
    source不能用于多对多的关联

序列化高级用法之定制字段的两种方式

SerializerMethodField定制

需求:
    定制关联字段的显示形式
        一对多的显示为字典
        多对多的显示为列表套字典
        
class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()

    # 定制返回格式
    publish_detail = serializers.SerializerMethodField()
    # SerializerMethodField方法必须搭配一个get方法使用,且get方法后面的名字必须与上面的变量名相同
    def get_publish_detail(self, obj):
        # 返回什么前台就展示什么
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

    author_list = serializers.SerializerMethodField()

    def get_author_list(self, obj):
        l = []
        for author in obj.authors.all():
            l.append({'name': author.name, 'phone': author.phone})
        return l
    
总结:
    1.SerializerMethodField必须搭配一个方法使用
    2.搭配的方法名必须为get_定制的字段名
    3.搭配的方法返回什么,该字段在前台就展示什么

在表模型中定制

表模型中(models.py)
class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 留住,还有很多
    authors = models.ManyToManyField(to='Author')

    @property  # 伪装,将方法伪装成属性,在这里可以不写
    def publish_detail(self):
        # 返回什么前台就显示什么
        return {'name': self.publish.name, 'addr': self.publish.addr}

    @property
    def author_list(self):
        l = []
        for author in self.authors.all():
            l.append({'name': author.name, 'phone': author.phone})
        return l

序列化类中
class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8)
    price = serializers.CharField()
  
    # 定义的字段类型需要与模型类中返回的数据类型一致
    publish_detail = serializers.DictField()  # 写在序列化类中的字段需要先在模型类中定义出来
    author_list = serializers.ListField()

多表关联的反序列化保存

新增图书接口

前端传入的数据格式:{name:红楼梦,price:19,publish:1,authors:[1,2]}  # publish和authors填写的是出版社主键值
视图类
    class BookView(APIView):
        def post(self, request):
            ser = BookSerializer(data=request.data)
            if ser.is_valid():
                ser.save()
                return Response({'code': 100, 'msg': '新增成功'})
            else:
                return Response({'code': 101, 'msg': ser.errors})
            
序列化类
    class BookSerializer(serializer.Serializer):
        # name和price既要做序列化又要做反序列化,不用加read_only,write_only
        name = serializer.CharField(max_length=8)
        price = serializer.CharField()
        # 只做序列化,加read_only
        publish_detail = serializer.DictField(read_only=True)
        author_list = serializer.ListField(read_only=True)
        # 只做反序列化,加write_only
        publish = serilizer.CharField(write_only=True)
        authors = serializer.ListField(write_only=True)
        
        # 新增要重写create方法
        def create(self, validated_data):
            book = models.Book.objects.create(name=validated_data.get('name'), price=validated_data.get('price'), publish_id=validated_data.get('publish'))
            book.authors.add(*validated_data.get('authors'))
            return book

修改图书接口

前端传入格式与新增图书相同
视图类:
    class BookDetailView(APIView):
        def put(self, request, pk):
            book = models.Book.objects.filter(pk=pk).first()
            ser = BookSerializer(data=request.data, instance=book)
            if ser.is_valid():
                ser.save()
                return Response({'code': 100, 'msg': '修改成功'})
            else:
                return Response({'code': 101, 'msg': ser.errors})
            
序列化类:
    class BookSerializer(serializer.Serializer):
        # name和price既要做序列化又要做反序列化,不用加read_only,write_only
        name = serializer.CharField(max_length=8)
        price = serializer.CharField()
        # 只做反序列化,加write_only
        publish = serilizer.CharField(write_only=True)
        authors = serializer.ListField(write_only=True)
        
        # 重写undate方法
        def update(self, instance, validated_data):
            # validated_data存储的是校验过后的数据
            instance.name = validated_data.get('name')
            instance.price = validated_data.get('price')
            instance.publish_id = validated_data.get('publish_id')
            # authors是一个列表,需要先清空然后再添加 
            authors = validated_data.get('authors')
            instance.authors.clear()
            instance.authors.add(*authors)
            instance.save()
            return instance

ModelSerializer使用

ModelSerializer继承自Serializer它直接帮我们完成了一些操作
使用:
    class BookSerializer(serializer.ModelSerializer):
        class Meta:
            model = Book  # 与表建立关系
            # fields = '__all__'  # 直接序列化表中所有字段,也可以在列表中填写要序列化的字段,fields为固定写法
            # 在Meta中写了fields,就相当于在这了复制了表模型中所有的字段
            fields = ['name', 'price', 'public_detail', 'authors_list', 'publish', 'authors']
            # 定制反序列化时给字段类加属性,也可以直接重写字段
            extra_kwargs = {'name': {'max_length': 8},
                            'publish_detail': {'read_only': True},
                            'author_list': {'read_only': True},
                            'publish': {'write_only': True},
                            'authors': {'write_only': True},
                           }
            
posted on 2023-04-07 20:50  zyg111  阅读(32)  评论(0编辑  收藏  举报