DRF之Serializer序列化组件

序列化类Serializer的使用

serializers序列化组件:

  • 序列化过程:可以把我们用ORM产生的QuerySet对象转换成json格式数据;
  • 反序列化过程:可以实现数据校验功能,并把客户端发送过来的数据(前端json格式字符串),经过request.data以后变成字典,再把字典转成模型,存到数据库;

简单使用

模型层:

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()

创建序列化类:不想序列化的字段不写就行,建议新建py文件专门存放序列化类。

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    name = serializers.CharField()  # 与模型层字段类型对应
    price = serializers.IntegerField()  # 与模型层字段类型对应

视图层:

class BookAPIView(APIView):
    def get(self, request):
        # 取出所有图书的queryset对象
        books = models.Book.objects.all()
        # instance:要序列化的对象
        # many:是否有多条数据,只有一条数据就不用传many参数
        ser = serializer.BookSerializer(instance=books, many=True)
        # 序列化后的数据
        print(ser.data)
        return Response(ser.data)

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

常见字段

跟模型层的字段一样,但比模型层的字段多几个:

BooleanField()
NullBooleanField()
CharField()
EmailField()
RegexField()
SlugField()
URLField()
UUIDField()
IPAddressField()
IntegerField()
FloatField()
DecimalField()
DateTimeField()
DateField()
TimeField()
ChoiceField()
FileField()
ImageField()

serializer独有字段:

ListField()
DictField()

常见字段参数

serializer中的字段参数是用来反序列化时校验用的。

CharField()

参数 作用
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符

IntegerField()

参数 作用
max_value 最小值
min_value 最大值

通用参数

参数 作用
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
error_messages 包含错误编号与错误信息的字典

序列化类Serializer的反序列化

Serializer类还可以帮我们把前端传来的数据进行校验后反序列化,并保存到数据库中。

简单使用

模型层models.py:

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()

Serializer类:

class BookSerializer(serializers.Serializer):
    # 校验前端数据时name字段长度不能超过8位
    name = serializers.CharField(max_length=8)
    price = serializers.IntegerField()
	# 新增数据,validated_data是符合条件的字段数据
    def create(self, validated_data):
        book_obj = models.Book.objects.create(**validated_data)
        return book_obj
    # 修改数据,validated_data是符合条件的字段数据
    # instance是要修改数据的对象
    def update(self, instance, validated_data):
        # 修改name字段值
        instance.name = validated_data.get('name')
        # 修改price字段值
        instance.price = validated_data.get('price')
        instance.save()
        return instance

视图层views.py:

class BookAPIView(APIView):
    
    def post(self, request):
        # 前端数据传给data参数
        ser = BookSerializer(data=request.data)
        # 校验数据是否符合规范
        if ser.is_valid():
            ser.save()
            return Response({'msg':'添加成功'})
        return Response({'msg':'添加失败'})
    
    def put(self, request, bid):
        book_obj = models.Book.objects.filter(pk=bid).first()
        ser = BookSerializer(instance=book_obj, data=request.data)
        # 校验数据是否符合规范
        if ser.is_valid():
            ser.save()
            return Response({'msg':'修改成功'})
        return Response({'msg':'修改失败'})

重点

  • 保存到数据库中用的是Serializer类中的save()方法
  • 在使用save()方法前需要先使用is_valid()校验数据
  • 添加数据,Serializer类需要自行编写create()方法
  • 修改数据,Serializer类需要自行编写update()方法
  • 执行save()方法是会判断对象中是否有instance参数,无则执行create()方法,有则执行update()方法
  • validated_data是符合条件的字段数据
  • create()方法和update()方法需要返回新增的对象和修改后的对象

update()优化写法:如果validated_data没有某个字段,则该字段值用原来的字段值。

def update(self, instance, validated_data):
    instance.name = validated_data.get('name', instance.name)
    instance.price = validated_data.get('price', instance.price)
    instance.save()
    return instance

常见方法和属性

方法与属性 含义
save() 保存到数据库
is_valid() 校验数据是否符合规范
errors 数据校验失败的原因
validated_data 符合条件的数据(只有is_valid()为True才有数据)
data 创建对象时传的数据
instance 创建对象时传的模型层对象

image

局部和全局钩子

局部和全局钩子可以再字段校验后进行二次校验。

局部钩子

写在序列化类中的局部钩子函数,校验单个字段。

使用:创建函数名 validate_ + 字段名

from rest_framework import serializers
from rest_framework.serializers import ValidationError

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8)
    price = serializers.IntegerField()
	
    def validate_name(self, name):
        """name参数为校验字段值"""
        # 判断name字段值是否已'aa'开头
        if name.startwith('aa'):
            # 有则抛异常
            raise ValidationError('不能已aa开头')
        # 符合规范返回字段值
        return name

全局钩子

写在序列化类中的全局钩子函数,校验所有字段。

使用:创建函数名 validate

from rest_framework import serializers
from rest_framework.serializers import ValidationError

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=8)
    price = serializers.IntegerField()
	
    def validate(self, attrs):
        """attrs参数为校验后的字段数据"""
        
        name=attrs.get('name')
        price=attrs.get('price')
        # 判断name字段是否等于price字段
        if name == price:
            # 等于则抛异常
            raise ValidationError('名字和价格不能一样')
        # 符合规范返回字段数据
        return attrs

校验流程:先走字段自己的校验规则,再走局部钩子,再走全局钩子。

序列化类ModelSerializer

ModelSerializer类可以快速完成Serializer类的功能,自动对应模型层的字段。

基本使用

from rest_framework import serializers

class BookSerializer(serializers.ModelSerializer):
    # 必要
    class Meta:
        # 指定模型层中的类
        model = Book
        # 指定字段
        fields = ['name',]
        """
        fields = '__all__ 指定所有字段'
        """
        # 添加字段校验属性
        extra_kwargs = {
            'name':{  # 指定name字段长度不能超过8位
                'max_length':8,
            },
        }

也可以把字段单独拿出来:

from rest_framework import serializers

class BookSerializer(serializers.ModelSerializer):
    # 必要
    class Meta:
        ...
    name = serializers.CharFields(max_length=10)

ModelSerializer类的重点:

  • 不需要重写create()和update()方法了
  • 局部钩子和全局钩子使用方法和Serializer类一样,注意不要写在Meta类中
  • 可以单独重写字段
  • 给字段类加属性用extra_kwargs

多表序列化与反序列化

在有外键字段存在时,如果直接把表进行序列化展示,外键字段显示的是外键id值,如果我们想要外键字段的详细信息,并且在添加数据时不会被干扰,可以做如下操作。

现我有如下表:

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()

    # 外键字段
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)

class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

方法一:在序列化类中编写

ModelSerializer类:

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = [
            'name',
            'price',
            'publish',
            'publish_detail',
        ]
        # 设置Book表的publish字段为只用于写入
        extra_kwargs = {
            'publish':{'write_only':True}
        }
    # 重写字段,这个字段属性read_only默认为True
    # 所以不用添加read_only属性
    publish_detail = serializers.SerializerMethodField()
    # 配合函数一起使用
    def get_publish_detail(self, obj):
        """
        obj是Book表对象
        返回值:这里返回什么,publish_detail就显示什么
        """
        return {
            'name': obj.publish.name,
            'email': obj.publish.email,
        }

方法二:在模型类中编写

模型层:

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()

    # 外键字段
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    
    # 添加一个函数返回publish字段
    def publish_detail(self):
        return {
            'name': self.publish.name,
            'email': self.publish.email,
        }

ModelSerializer类:

from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = [
            'name',
            'price',
            'publish',
            'publish_detail',  # 这里指的是模型层中的函数
        ]
        # 设置Book表的publish字段为只用于写入
        extra_kwargs = {
            'publish':{'write_only':True}
        }
posted @ 2022-06-15 14:56  Yume_Minami  阅读(170)  评论(0编辑  收藏  举报