django restfremwork serializer的validate机制

       使用DRF去创建标准API的时候有一个日常操作就是serializer.is_valid(),用于检查序列化对象serializer是否合规,这个方法有一个参数叫raise_exception(boolean值),用于控制是不是抛出错误啥的。在自定义的serializer内自定义validate,方法名用validate和要做特殊检查的字段用下划线连起来命名就可以直接检查,比如要实现一个需求,邻居都不能姓王,那么就需要在自己对应的serializer内新增一个叫做validata_name的方法,可以这样写

class NeighbourSerializer(serializers.Serializer):
    """
    邻居们的序列化
    """

    ......
    ......
    name = serializers.CharField(max_length=100, allow_null=False)
    def validate_name(self, value):
        if value.first_name == '王':
            raise serializers.ValidationError(u'隔壁怎么可以姓王?')

        这个时候当代码运行起来会发现is_valid()时会自动进行检查,假如是我,我估计是拼接字符串,validate_当标志,后面拼上field名称当方法名然后调用。但是依然很好奇框架作者大神是如何实现的,所以看了看源码,整个调用流程是从is_valid()方法开始的,is_valid()内部会调用run_validation(data),然后run_validation()(注意,这个run_validation是Serializer类的,而不是Field的,rest_fremwork下自己封装的field也有一套名称一模一样的方法,跟踪的时候容易跟错),然后在run_validation内部会调用另外一个方法,叫做to_internal_value(data),这个方法是自定义validate的关键,源码如下:

def to_internal_value(self, data):
    """
    Dict of native values <- Dict of primitive datatypes.
    基本数据类型  ->  本地数据类型(我理解就是Serializer自己认的数据类型),顾注释思义!这玩意儿是用来使数据类型啥的变成合 乎自己逻辑的。
    """
    if not isinstance(data, Mapping):
        message = self.error_messages['invalid'].format(
            datatype=type(data).__name__
        )
        raise ValidationError({
            api_settings.NON_FIELD_ERRORS_KEY: [message]
        }, code='invalid')

    ret = OrderedDict()
    errors = OrderedDict()
    fields = self._writable_fields

    for field in fields:
        # 这里的fields内容就是我们在自定义的Serializer子类内标明的字段
        validate_method = getattr(self, 'validate_' + field.field_name, None)
        # 这一行果不其然用字符串拼接方法名的方式去获取对应的validate方法
        primitive_value = field.get_value(data)
        try:
            validated_value = field.run_validation(primitive_value)
            # 这一行就是上面说道的field也有一套validate的方法用于校验字段
            if validate_method is not None:
                validated_value = validate_method(validated_value)
                # 此处对自定义的validate方法进行了调用
        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

结论:

1.自定义validate底层就是使用的字符串拼接,所以在使用这个机制的时候尽量复制粘贴field的名称避免单词拼写问题。

2.方法内读取的fields是直接self内去获取的Serializer自身定义过的field而不是Model内的,所以要使用这一机制,务必在自己的Serializer内创建对应的field.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值