from wtforms_tornado import Form class ModelForm(Form): """ 模型表单。派生后主要处理以下内容:: 有可能在 formdata 中出现的非列表类型,统一转为列表类型。 """ def __init__(self, formdata=None, obj=None, prefix="", data=None, meta=None, **kwargs): """ 构造模型表单。 :param formdata: 来自客户端的输入数据,通常为 request.form 或等效数据。应该提供一个 multi-dict 接口来获取给定键的值列表。 :param obj: 从该对象上与表单字段属性匹配的属性中获取现有数据。仅在未传递 formdata 时使用。 :param prefix: 如果提供,所有字段的名称都将以值为前缀。这是为了区分单个页面上的多个表单。这只会影响匹配输入数据的 HTML 名称,而不会影响匹配现有数据的 Python 名称。 :param data: 从该 dict 中与表单字段属性匹配的键中获取现有数据,如果 obj 也有匹配的属性,则它优先。仅在未传递 formdata 时使用。 :param meta: 要在此窗体的 :attr: meta 实例上重写的属性 dict。 :param kwargs: 与 data 合并以允许将现有数据作为参数传递。覆盖 data 中的任何重复键。仅在未传递 formdata 时使用。 """ if isinstance(formdata, dict): # 对有可能在 formdata 中出现的非列表类型,统一转为列表类型 formdata = {k: list(v) if isinstance(v, (list, tuple, set)) else [f'{v}'] for k, v in formdata.items()} # 启动父类构造 super(Form, self).__init__(formdata=formdata, obj=obj, prefix=prefix, data=data, meta=meta, **kwargs) @classmethod def list_to_field_list(cls, formdata, field_name: str, separator: str = '-'): """ 将 list 数据转换为符合 FieldList 的赋值规则的字段数据,即转换为 字段名+隔符+下标 格式的表单数据。 :param formdata: 来自客户端的输入数据 :param field_name: 字段名 :param separator: 分隔符,默认与 FieldList 一致为 "-" 符号 """ # 当以 JSON 数组传入时,转换为以 - 连接的字段项,以符合 FieldList 的赋值规则 _value_list = formdata.get(field_name, []) if _value_list and isinstance(_value_list, list): for _idx, _item in enumerate(_value_list): formdata[f"{field_name}{separator}{_idx}"] = _item def validate_form(self, auto_raise: bool = True): """ 验证表单数据。 :param auto_raise: 当该参数为 True 时,若验证不成功,抛出验证异常。 :return: 验证结果 """ validate_result = {} if self.validate(): return True, validate_result else: validate_result.update(self.errors.items()) if auto_raise: raise Exception('数据验证错误!', {'form_data': self.data, 'form_errors': validate_result}) return False, validate_result