自定义字段类型的验证类

一、前言

都是跟别人的代码写的

二、代码

"""
字段类型的验证类
"""
from datetime import datetime

from 工具.motorORM.校验异常 import FieldValidationError, Maxlength, MinAndMaxInt, Regx, MinAndMaxFloat, EmailRegx, UrlRegx


def is_iterable(x):
    "An implementation independent way of checking for iterables"
    try:
        iter(x)
    except TypeError:
        return False
    else:
        return True


EMPTY_VALUES = (None, '', [], (), {})


class Field:
    """
    字段的基类
    verbose_name: 字段的描述,和help_text重复了,删除
    name: 字段的键名
    primary_key: 主键约束
    max_length: 字符串长度
    unique: 唯一属性
    blank: 空字段,类似“”{}()【】等
    null: 空属性,类似None
    default: 默认值
    editable: 可编辑性,默认可编辑
    unique_for_date: 天唯一
    unique_for_month: 月唯一
    unique_for_year: 年唯一
    choices: 可选数据,Django使用元祖形式,不可改变,我想换成字典
    help_text: 帮助信息
    auto_created: 自动创建,没用,删除
    validators: 验证类
    db_index=False: 索引,没用,删除
    serialize: 序列化,没用,删除
    required: 将 null和blank删除,添加require代替

    field_name: 字段名,过滤用的
    lookup_expr: 过滤的规则

    regx: 正则校验
    """
    empty_value = list(EMPTY_VALUES)

    def __init__(self, *, datatype=None, regx=None,
                 unique=False, required=True, field_name=None, lookup_expr=None,
                 default=None, editdisable=True,
                 unique_for_date=None, unique_for_month=None,
                 unique_for_year=None, choices=None, help_text='',
                 validators=()):
        """
        根据传入的属性,创建校验流程
        每个具体的子类,向validators里面添加具体的验证类即可
        """
        self.datatype = datatype
        self.name = None  # 留个位置存放实例名字
        self.value = None  # 留个位置存放值
        self.unique = unique
        self.required = required
        self.default = default
        self.editdisable = editdisable
        self.unique_for_date = unique_for_date
        self.unique_for_month = unique_for_month
        self.unique_for_year = unique_for_year
        self.choices = choices
        self.help_text = help_text
        self.validators = list(validators)
        self.regx = regx
        # 如果没有定义字段名,就默认使用name属性
        if not field_name:
            self.field_name = self.name
        else:
            self.field_name = field_name
        # 高级过滤字段
        self.lookup_expr = lookup_expr
        if self.regx:
            self.validators.append(Regx(self.regx))

    def check(self, ):
        # 1.检查实例名是不是合法的,
        # 2.choice的类型是不是可遍历类型且不能是字符串
        # 3.validators里面的是不是可以callable
        self.check_name()
        self.check_validators()
        self.check_choices()

    def check_name(self):
        # 检查field_name,不能有“__”,不能用pk关键字,
        if "__" in self.name:
            raise FieldValidationError({self.name: f"{self.name}不能有‘__’"})
        if self.name == "pk":
            raise FieldValidationError({self.name: f"{self.name}不能是‘pk’关键字"})

    def check_validators(self):
        for i, validator in enumerate(self.validators):
            if not callable(validator):
                raise FieldValidationError({self.name: f"{self.name}的验证类{validator}类型错误"})

    def check_choices(self):
        if not self.choices:
            self.choices = []

        if not is_iterable(self.choices) or isinstance(self.choices, str):
            raise FieldValidationError({self.name: f"{self.name}的choices参数必须是可遍历对象且不能是字符串类型"})

    def transformation_type(self):
        # 类型转换,
        pass

    def getmodelfield(self):
        # 获取模型字段的值
        if not self.value and self.default:
            self.value = self.default
        return {self.name: self.value}

    def getfilterfield(self):
        # 获取过滤字段的值
        if self.lookup_expr:
            return {self.name: {f"${self.lookup_expr}": self.value}}
        else:
            return {self.field_name: self.value}

    def validate(self):
        # 主要的校验过程
        # 1.校验类型
        # 2.使用self.validators里面的验证类进行校验
        # 3.验证value是不是在choices里面
        # 首先验证是不是必填的
        if not self.value and self.required:
            raise FieldValidationError({self.name: f"{self.name}是必填的,不能空。"})
        if not self.value and not self.required:
            # 如果是空的,并且允许为空,停止校验
            return False
        # 如果不是空的,先进行数据类型转换
        self.transformation_type()
        if self.choices and self.value not in self.choices.keys():
            raise FieldValidationError({self.name: f"{self.name}必须在{self.choices}里面"})
        if self.datatype and not isinstance(self.value, self.datatype):
            raise FieldValidationError({self.name: f"{self.name}应该是{self.datatype}类型,但得到的是{type(self.value)}类型"})
        for i in self.validators:
            i(self.name, self.value)

    def __str__(self):
        if self.value:
            return str(self.value)
        else:
            return "空的"

    def __getitem__(self, item):
        return self.__dict__[item]

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __set__(self, instance, value):
        self[instance] = value
        if instance == "name":
            self.check()
        elif instance == "value":
            self.validate()


class StringField(Field):
    """
    字符串校验
    """

    def __init__(self, max_length, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.max_length = max_length
        self.validators.append(Maxlength(self.max_length))
        self.datatype = str

    def transformation_type(self):
        self.value = str(self.value)


class NumberField(Field):
    """
    数字校验
    """

    def __init__(self, min_item=None, max_item=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.min_item = min_item
        self.max_item = max_item
        self.validators.append(MinAndMaxInt(self.min_item, self.max_item))
        self.datatype = int

    def transformation_type(self):
        self.value = int(self.value)


class FloatField(Field):
    """
    浮点数校验
    """

    def __init__(self, min_item=None, max_item=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.min_item = float(min_item)
        self.max_item = float(max_item)
        self.validators.append(MinAndMaxFloat(self.min_item, self.max_item))
        self.datatype = float

    def transformation_type(self):
        self.value = float(self.value)


class EmailField(StringField):
    """
    邮箱校验
    """

    def __init__(self, *args, **kwargs):
        kwargs["regx"] = None
        kwargs["max_length"] = None
        super().__init__(*args, **kwargs)
        regx = r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"
        self.validators.append(EmailRegx(regx))


class UrlField(StringField):
    """
    地址的校验
    """

    def __init__(self, *args, **kwargs):
        kwargs["regx"] = None
        kwargs["max_length"] = None
        super().__init__(*args, **kwargs)
        regx = r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+"
        self.validators.append(UrlRegx(regx))


class BoolField(Field):
    """
    布尔值校验
    """

    def __init__(self, *args, **kwargs):
        kwargs["regx"] = None
        super().__init__(*args, **kwargs)
        self.datatype = bool

    def validate(self):
        # 布尔值的验证需要重写
        if self.value is not None and not isinstance(self.value, bool):
            raise FieldValidationError({self.name: f"{self.name}必须是布尔值或者None。"})


class DateTimeField(Field):
    """
    日期加时间类型
    """

    def __init__(self, *args, **kwargs):
        kwargs["regx"] = None
        super().__init__(*args, **kwargs)
        self.datatype = datetime

    def getmodelfield(self):
        # 获取模型字段的值
        if not self.value and self.default == 'auto_add':
            self.value = datetime.now()
            self.value = self.default
        return {self.name: self.value}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值