一、前言
都是跟别人的代码写的
二、代码
"""
字段类型的验证类
"""
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}