
在 WTForms 2.x 中,FieldList 本身不支持顶层 Optional 验证器,直接对 FieldList 应用 Optional() 无效;需改用 request.form.get() + ast.literal_eval() 手动解析 JSON 格式字符串,再结合类型与范围校验,才能实现「未提交为 None、空数组为 []、有效数字为 [int, ...]」的语义。
在 wtforms 2.x 中,`fieldlist` 本身不支持顶层 `optional` 验证器,直接对 `fieldlist` 应用 `optional()` 无效;需改用 `request.form.get()` + `ast.literal_eval()` 手动解析 json 格式字符串,再结合类型与范围校验,才能实现「未提交为 `none`、空数组为 `[]`、有效数字为 `[int, ...]`」的语义。
WTForms 的 FieldList 设计初衷是配合 HTML 表单动态字段(如多次点击“添加”生成多个 <input>),其数据绑定依赖 每个子字段独立存在且命名连续(如 patch_bases-0, patch_bases-1)。而你的 curl --form 'patch_bases=[2, 4]' 实际将整个 JSON 数组作为单个表单字段值提交,形如 patch_bases=[2%2C+4](URL 编码后),这与 FieldList 期望的扁平化命名结构完全不匹配——因此 form.patch_bases.data 永远为空列表,无论是否传值。
✅ 正确做法:绕过 FieldList,手动解析表单字段
由于你同时上传文件(必须用 multipart/form-data),且 patch_bases 是 JSON 数组字符串,应直接从 request.form 提取并安全解析:
import ast
from flask import request
from wtforms import FlaskForm, FileField, StringField
from wtforms.validators import DataRequired, UUID
class PublishForm(FlaskForm):
file = FileField("Upload file", validators=[DataRequired()])
# 其他必填字段...
def publish_api():
form = PublishForm()
if not form.validate_on_submit():
return form_error_response(form.errors)
# 手动处理 patch_bases 字段(FieldList 不适用)
patch_bases_raw = request.form.get("patch_bases")
patch_bases = None # 默认为 None(字段未提交)
if patch_bases_raw is not None:
try:
# 安全解析 JSON-like 字符串,仅允许 list/int/literal
parsed = ast.literal_eval(patch_bases_raw)
if not isinstance(parsed, list):
raise ValueError("Not a list")
# 校验每个元素为 int,且总数 0–5
if len(parsed) > 5:
raise ValueError("Too many items (max 5)")
for i, item in enumerate(parsed):
if not isinstance(item, int):
raise TypeError(f"Item {i} is not an integer: {type(item).__name__}")
patch_bases = parsed
except (ValueError, TypeError, SyntaxError) as e:
return form_error_response({"patch_bases": [f"Invalid format: {e}"]})
# 此时 patch_bases 可能为 None / [] / [2, 4]
print("Parsed patch_bases:", patch_bases)
# 后续业务逻辑...
return {"status": "success", "patch_bases": patch_bases}
⚠️ 注意事项:
-
永远不要用
eval()——ast.literal_eval()仅允许list,int,float,str,bool,None字面量,杜绝代码注入风险; -
request.form.get("patch_bases")返回str或None,不会自动 JSON 解析(request.get_json()在multipart中不可用); - 若需强类型校验(如负数限制、唯一性),应在
parsed后追加自定义检查; - 升级 WTForms ≥3.0 后,可尝试
FieldList(IntegerField(), min_entries=0)配合JSONField或自定义FieldList子类,但当前 2.0.2 版本无原生支持,手动解析是最稳定方案。
总结:FieldList ≠ JSON 数组解析器。当 API 接收结构化数据(如 patch_bases=[2,4])时,应放弃 FieldList 绑定,转而使用 request.form.get() + ast.literal_eval() 进行显式、可控、安全的解析,并辅以清晰的错误反馈。











