You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 18:27:49