DRF---序列化组件

目录

序列化器Serializer

序列化组件基本使用

使用序列化类, 序列化多条数据

使用序列化类,序列化单条数据

反序列化(新增, 修改)

新增

视图类

序列化类

视图类

序列化类

序列化类的常见字段类和常见参数

常用字段类型

 选项参数

通用参数

 常用的字段类型

 常用字段参数

补充

序列化类之source

 定制序列化类的两种方式

在序列号类中写SerializerMethodField

在模型类中定义方法

反序列化之数据校验

字段自己的校验规则

局部钩子

全局钩子

模型类序列化器[ModelSerializer]的使用

反序列化数据校验源码分析


DRF序列化组件是drf提供的一个类, rest_framework.serializers.Serializer, 我们可以继承它来写自己的类. 

序列化器Serializer

作用:

1. 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
3. 反序列化,完成数据校验功能

序列化组件基本使用

 开一个py文件serializer,定义一个序列化类

from rest_framework import serializers

# 写序列化类. 给book序列化
class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()




使用序列化类, 序列化多条数据

class BookView(APIView):
    def get(self,request):
        book_list = Book.objects.all()
        ser = BookSerializer(instance=book_list,many=True)
        return Response(ser.data)

instance 表示要序列化的数据, many=True表示序列化多条,  instance是queryset对象, 一定要传many=True

使用序列化类,序列化单条数据


class BookDetailView(APIView):
    def get(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)

反序列化(新增, 修改)

新增

视图类

# 反序列化, 新增
class BookView(APIView):  # APIView继承自django的View
    def get(self,request):
        book_list = Book.objects.all()
        ser = BookSerializer(instance=book_list,many=True)
        return Response(ser.data)


    def post(self,request):
        # 前端传递数据, 从request.data取出来
        ser = BookSerializer(data=request.data)
        if ser.is_valid():  # 表示校验前端传入的数据, 没有写校验规则, 现在等于没有校验
            ser.save()  # 在写东西这里就会报错, 调用save方法, 判断 如果instance有值执行update, 没有值就执行create
            return Response(ser.data)
        else:
            return Response(ser.errors)

序列化类

    def create(self,validated_data):
        res = Book.objects.create(**validated_data)
        return res

视图类

# 修改
class BookDetailView(APIView):
    def get(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)
    
    def put(self,request,pk):
        book = Book.objects.filter(pk=pk).first()
        # 前端传递数据, corequest.data取出来
        ser = BookSerializer(instance=book,data=request.data)
        if ser.is_valid():  # 表示校验前端传入的数据, 没有写校验规则就等于没校验
            ser.save()  # 在写东西就会报错, 调用save会触发BookSerizlizer的save方法, 判断, 如果instance有值执行update, 没有执行create
            return Response(ser.data)
        else:
            return Response(ser.errors)

序列化类

    def update(self,instance,validated_data):
        # instance要修改的对象
        # validated_data校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()
        return instance
        

序列化类的常见字段类和常见参数

常用字段类型

字段字段构造方式
BooleanFieldBooleanField()
NullBooleanFieldNullBooleanField()
CharFieldCharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailFieldEmailField(max_length=None, min_length=None, allow_blank=False)
RegexFieldRegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugFieldSlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLFieldURLField(max_length=200, min_length=None, allow_blank=False)
UUIDFieldUUIDField(format=’hex_verbose’) format: 1) 'hex_verbose' 如"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex' 如 "5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressFieldIPAddressField(protocol=’both’, unpack_ipv4=False, **options)
IntegerFieldIntegerField(max_value=None, min_value=None)
FloatFieldFloatField(max_value=None, min_value=None)
DecimalFieldDecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeFieldDateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateFieldDateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeFieldTimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationFieldDurationField()
ChoiceFieldChoiceField(choices) choices与Django的用法相同
MultipleChoiceFieldMultipleChoiceField(choices)
FileFieldFileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageFieldImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListFieldListField(child=, min_length=None, max_length=None)
DictFieldDictField(child=)

 选项参数

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

通用参数

参数名称说明
read_only表明该字段仅用于序列化输出,默认False
write_only表明该字段仅用于反序列化输入,默认False
required表明该字段在反序列化时必须输入,默认True
default反序列化时使用的默认值
allow_null表明该字段是否允许传入None,默认False
validators该字段使用的验证器
error_messages包含错误编号与错误信息的字典
label用于HTML展示API页面时,显示的字段名称
help_text用于HTML展示API页面时,显示的字段帮助提示信息

 常用的字段类型


CharField
BooleanField
IntegerField
DecimalField

# 这两个是序列化列独有的
ListField: {name:'lqz',age:19,hobby:['篮球','足球']}  # 可以以列表存储
DictField:{name:'lqz',age:19,wife:{'name':'jason','age':18}}  # 可以以字典存储

 常用字段参数

# 给CharField字段使用的参数
max_length            最大长度
min_lenght            最小长度
allow_blank            是否允许为空
trim_whitespace    是否截断空白字符

# 给IntegerField字段类使用的参数
min_value        最小值
max_value       最大值

补充

 read_only 表明该字段只能用于序列化输出给前端或其他

write_only 表明该字段只能用于反序列化输入

序列化类之source

 该参数主要用于修改序列化字段的名字

# 现在我们编写了一个book表:

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



# 然后我们编写一个获取图书的接口 需要用到序列化类
class BookSerializer(serializers.Serializer):
    name = serializers.CharField(min_length=3, max_length=8)
    price = serializers.CharField(min_length=3, max_length=8)
    publish = serializers.CharField(min_length=3, max_length=8)

# 我们在使用序列化类 然后把书籍传到前端显示 接口
class BookView(APIView):
    def get(self, request):
        book_list = Book.objects.all()
        ser = BookSerializer(instance=book_list, many=True)
        return Response(ser.data)

序列化的字段名称是什么,前端就会返回什么

如果想要在前端的name字段显示book_name, 我们就可以使用source参数

   book_name = serializers.CharField(min_length=3, max_length=8, source='name')  # 字段名称写自己想要的 source后面跟上表的字段名称

 定制序列化类的两种方式

在序列号类中写SerializerMethodField

xxx = serializers.SerializerMethodField()

# obj是当前序列化类的对象
def get_xxx(self, obj):
    return {'name': obj.name}


# 获取书籍对象的所有作者
author = serializers.SerializerMethodField()
def get_author(self, book_obj):
	return [{'name': obj.name, 'age': obj.age, 'phone': obj.author_detail.phone} for obj in book_obj.author.all()]

在模型类中定义方法

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=6, decimal_places=2)
    create_time = models.DateField()
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
    author = models.ManyToManyField(to='Author')

    def __str__(self):
        return f'{self.name}'

    # 可以加property装饰 也可以不加 序列化组件可以不用加括号拿到
    @property
    def publish_detail(self):
        return {'name': self.publish.name, 'city': self.publish.city, 'email': self.publish.email}

    def author_list(self):
        return [{'name': obj.name, 'age': obj.age, 'phone': obj.author_detail.phone} for obj in self.author.all()]

有关联关系表数据创建

# 只写不读 只反序列化不序列化
publish = serializers.IntegerField(write_only=True)
author = serializers.ListField(write_only=True)

# 只读不写 只序列化不反向序列化
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)

# 继承serializers.Serializer一定要重写creata方法和update方法
def create(self, validated_data):
    name = validated_data.get('name')
    price = validated_data.get('price')
    create_time = validated_data.get('create_time')
    publish = validated_data.get('publish')
    author = validated_data.get('author')
    # 创建书籍数据
    obj = Book.objects.create(name=name, price=price, create_time=create_time, publish_id=publish)
    # 添加书籍和作者关系 多对多
    obj.author.add(*author)
    return obj


def update(self, instance, validated_data):
    name = validated_data.get('name')
    price = validated_data.get('price')
    create_time = validated_data.get('create_time')
    publish = validated_data.get('publish')
    author = validated_data.get('author')
    instance.name = name
    instance.price = price
    instance.create_time = create_time
    instance.publish_id = publish
    instance.author.set(author)
    instance.save()
    return instance

总结:继承Serializer的序列化组件需要写校验的每个字段,创建和修改数据时,需要重写create和update方法。而使用ModelSerializer,不需要写这些。

反序列化之数据校验

首先是校验字段自己的校验规则 , 通过后校验局部钩子,最后校验全局钩子

字段自己的校验规则

class BookSerializer(serializers.Serializer):
	# 继承Serializer字段自己的校验规则
    book_name = serializers.CharField(max_length=8, min_length=3, required=True,)
class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['name', 'price', 'create_time', 'publish', 'author', 'publish_detail', 'author_list']
        extra_kwargs = {
        	#继承ModelSerializer字段自己的校验规则
            'name': {'max_length': 8, 'min_length': 3},
            }

局部钩子

def validate_name(self, name):
    if 'sb' in name:
        raise ValidationError('名字不能包含敏感词')
    return name


def validate_price(self, price):
    if price == 66:
        raise ValidationError('价格不能是66')
    return price

全局钩子

def validate(self,attrs):
	if attrs.get('password') != attrs.get('re_password'):
		raise ValidationError('两次密码不一致')
	return attrs

模型类序列化器[ModelSerializer]的使用

1. 定义一个序列化组件类, 继承ModelSerializer.

2. 在序列化组件类中定义有个Meta类, 类中指定model和fields参数

3.在Meta类中指定extra_kwargs,给字段添加参数

4. 在序列化类中, 可以重写某个字段, 优先使用你重写的

5. 不需要再重写create 和 update方法

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        # fields = ['__all__'] 所有字段都序列化
        fields = ['name', 'price', 'create_time', 'publish', 'author', 'publish_detail', 'author_list']
        extra_kwargs = {
            'name': {'max_length': 8, 'min_length': 3},
            'price': {'min_value': 9, 'max_value': 199},
            'publish': {'write_only': True},
            'author': {'write_only': True},
            'publish_detail': {'read_only': True},
            'author_list': {'read_only': True},
        }

    def validate_name(self, name):
        if 'sb' in name:
            raise ValidationError('名字不能包含敏感词')
        return name

    def validate_price(self, price):
        if price == 66:
            raise ValidationError('价格不能是66')
        return price

反序列化数据校验源码分析

入口时序列化组件对象>> is_valid()方法

BaseSerializer里的is_valid

def is_valid(self, *, raise_exception=False):
		
    if not hasattr(self, '_validated_data'):
        try:
        	# 真正开始校验 如果校验成功返回校验通过的数据
            self._validated_data = self.run_validation(self.initial_data)
        except ValidationError as exc:
            self._validated_data = {}
            self._errors = exc.detail
        else:
            self._errors = {}

    if self._errors and raise_exception:
        raise ValidationError(self.errors)

    return not bool(self._errors)

执行self.run_validation(self.initial_data)

Serializer里的run_validation

def run_validation(self, data=empty):
    # 执行局部钩子
    value = self.to_internal_value(data)
    try:
    	# 执行全局钩子
        self.run_validators(value)
        value = self.validate(value)
        assert value is not None, '.validate() should return the validated data'
    except (ValidationError, DjangoValidationError) as exc:
        raise ValidationError(detail=as_serializer_error(exc))

    return value
    def to_internal_value(self, data):=
        for field in fields:
        	# 反射判断是否有局部钩子函数
            validate_method = getattr(self, 'validate_' + field.field_name, None)
            primitive_value = field.get_value(data)
            try:
            	# 字段本身的校验规则
                validated_value = field.run_validation(primitive_value)
                # 局部钩子校验
                if validate_method is not None:
                    validated_value = validate_method(validated_value)
            except ValidationError as exc:
                errors[field.field_name] = exc.detail
            except DjangoValidationError as exc:
                errors[field.field_name] = get_error_detail(exc)
            except SkipField:
                pass
            else:
                set_value(ret, field.source_attrs, validated_value)

        if errors:
            raise ValidationError(errors)

        return ret

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值