如何在Flask后端接收非扁平化字典格式的表单数据?
如何让WTForms返回非扁平化的嵌套字典数据?
嘿,这个问题我之前也碰到过——WTForms的FormField默认就是会把嵌套字段的名字用连字符拼起来,导致最终拿到的是扁平化的数据。要得到你想要的嵌套字典结构,有几个实用的方案可以试试:
方案一:自定义嵌套表单字段(最推荐)
我们可以重写FormField的行为,让它生成带括号的字段名(比如input[input_type]),这样Flask会自动把提交的数据解析成嵌套字典,同时保留表单验证的功能。
先写一个自定义的NestedFormField类:
from wtforms.fields import FormField as WTFormField class NestedFormField(WTFormField): def _get_subfield_name(self, name): # 把默认的连字符格式改成括号嵌套格式 return f"{self.name}[{name}]" def process(self, formdata, data=None): # 手动提取嵌套的表单数据段,适配新的字段名格式 if formdata: nested_data = {} prefix = f"{self.name}[" for key, value in formdata.items(): if key.startswith(prefix): # 提取括号里的字段名 nested_key = key[len(prefix):-1] nested_data[nested_key] = value super().process(nested_data, data) else: super().process(formdata, data)
然后修改你的ConfigForm,用这个自定义字段代替原来的FormField:
class ConfigForm(FlaskForm): input = NestedFormField(InputForm) device_type = wtforms.StringField("Device type")
这样一来,前端渲染的字段name会变成input[input_type]、input[path],提交后你直接从form.data就能拿到完美的嵌套字典了:
@app.route('/submit', methods=['POST']) def submit(): form = ConfigForm() if form.validate_on_submit(): print(form.data) # 输出就是你要的格式:{'device_type': '2', 'input': {'input_type': '3', 'path': '', ...}} return "Success" return "Invalid form"
方案二:手动重组表单数据(快速解决)
如果不想折腾自定义字段,也可以在视图里手动把扁平化的数据拼成嵌套结构,简单直接:
@app.route('/submit', methods=['POST']) def submit(): form = ConfigForm() if form.validate_on_submit(): # 手动构建嵌套字典 nested_data = { 'device_type': form.device_type.data, 'input': { field_name: field.data for field_name, field in form.input._fields.items() } } print(nested_data) return "Success" return "Invalid form"
这种方法不需要修改任何表单类,适合快速解决问题,尤其是嵌套字段不多的情况。
方案三:手动修改模板字段名(繁琐但灵活)
Flask本身支持解析带括号的字段名,所以你也可以在模板里手动指定每个嵌套字段的name属性,让提交的数据自动被解析成嵌套结构:
在模板里这么写:
<form method="POST"> {{ form.hidden_tag() }} <div> {{ form.device_type.label }} {{ form.device_type() }} </div> <div> {{ form.input.input_type.label }} <input type="text" name="input[input_type]" value="{{ form.input.input_type.data }}"> </div> <div> {{ form.input.path.label }} <input type="text" name="input[path]" value="{{ form.input.path.data }}"> </div> <!-- 其他嵌套字段同理 --> <button type="submit">提交</button> </form>
然后在视图里直接从request.form获取嵌套数据:
@app.route('/submit', methods=['POST']) def submit(): # request.form会自动解析嵌套结构 print(request.form.get('device_type')) print(request.form.get('input[input_type]')) # 或者转成字典再手动整理 data = request.form.to_dict() nested_data = { 'device_type': data['device_type'], 'input': { 'input_type': data['input[input_type]'], 'path': data['input[path]'] } } return "Success"
不过这种方法需要手动渲染每个嵌套字段,字段多的话会比较麻烦,适合小场景使用。
总的来说,方案一是最省心的,一次修改就能让表单自动支持嵌套结构,后续添加字段也不用额外处理。
内容的提问来源于stack exchange,提问作者Cardano
相关产品推荐
相关产品推荐

