在Flask、Python与 SQLAlchemy中创建一个二维数据表

人工智能 2026-07-12

我对Python的 Flask还算新手,正在做一个基于网页的应用来支持一个简单的选项研究工具。我把网页表单中的数据保存到一个SQLite数据库,使用SQLAlchemy。

应用有三个输入表单。第一个接收处理选项的数量(num_options),第二个表单输入用于评判这些选项的若干标准(num_criteria)。第三个表单——也是问题所在——包含一个具有num_options行和num_criteria列的表格,每个表单项都包含一个“分数”(其中num_score = num_options * num_criteria)。下面给出一个示例——在这个示例中num_options = 3,num_criteria = 4。

注:前两个表单在各方面都能正常工作,因此Flask的表示和数据库文件结构都能工作——我的问题特指第三个Scores表单。下面显示的是Scores表单的格式。

|            | criteria(1) | criteria(2) | criteria(3) | criteria(4) |
|:----------:|:-----------:|:-----------:|:-----------:|:-----------:|
|  option(1) | score(1,1)  |  score(1,2) |  score(1,3) |  score(1,4) |
|  option(2) | score(2,1)  |  score(2,2) |  score(2,3) |  score(2,4) |
|  option(3) | score(3,1)  |  score(3,2) |  score(3,3) |  score(3,4) |

我正在把表单数据输入到SQLite数据库,使用SQLAlchemy。

我希望,提交按钮在SQLite数据库中创建一个数据表,格式如下:

| score_id | option_id | criteria_id | score |
|:--------:|:---------:|:-----------:|:-----:|
|    1     |    1      |      1      |  45   |
|    2     |    1      |      2      |  73   |
|    3     |    1      |      3      |  44   |
|    4     |    1      |      4      |  22   |
|    5     |    2      |      1      |  34   |
|    6     |    2      |      2      |  95   |

...等,总行数为 (num_options * num_criteria)。

我的问题是,当我将数据提交到所示的表中时,所有的Scores都会被保存为左上角的表单项的值。前三列输入正确。

Python/Flask/SQLAlchemy(如你所知)有三个组成部分:

“case”语句将Python代码与数据库表和HTML代码连接起来。我没有在Scores表单中使用FormField或 FieldList,因为我尝试按照AI给出的建议让它工作,但它会抛出错误,似乎与HTML渲染表单有关。我还使用了两个可变长度的列表,我认为它们无法应对,因为它们似乎提供了一个固定长度的可变长度列表。

Python/Flask渲染 表单。我在下面显示相关代码段。很可能问题出在db.session.add(...的代码行,因为它的最终部分 "scores = form.scores.data" 没有办法遍历表单项——我还没有找到任何参考说明告诉我应该如何做。

    @app.route('/scoring', methods=['GET', 'POST'])
    def scoring():
    # there are several lines removed here that are not relevant to this issue

        form = ScoresForm()

        db.session.query(Scores).delete()
        if form.validate_on_submit():
            for option in all_option_ids:
                for criterion in all_criteria_ids:
                    db.session.add(Scores(option_id=option, criteria_id=criterion, scores = form.scores.data))
            db.session.commit() 
            flash('Scores Saved!')
            return redirect(url_for('scoring'))

HTML/Jinja显示 表单与数据链接。再次,我把包含Scores部分的HTML代码段贴在下面——这段代码显示了我上面附的图片。尽管代码创建了一个3×4的 Scores表单,允许用户输入12个数字,但只有第一项(左上角)实际被保存到数据表中(会重复保存)。

    {% for options in options %}
        <th>{{ options.option_name }}</th>
        {% for criteria in criteria %}
            <td>
                {{ form.scores(class="form-input") }}
            </td>
        {% endfor %}
    {% endfor %}

如何重写它以实现我的目标,可能通过包含某种方式遍历表单中的所有项,或使用Flask的其他能力来捕获表单中的所有数据(例如放入一个列表),以便我能重新组织并保存?

解决方案

同一个字段在循环中始终由 {{ form.scores(...) }} 渲染,并且包含相同的 name 属性,因此浏览器只提交了一个值。

解决方法是给每个输入框一个唯一的名字,例如 score_1_2,表示每个单元格都有不同的字段名,可以直接查找。

在HTML中为每个输入框赋予唯一的名字

{% for option in options %}
    <th>{{ option.option_name }}</th>
    {% for criterion in criteria %}
        <td>
            <input type="number" name="score_{{ option.id }}_{{ criterion.id }}" class="form-input">
        </td>
    {% endfor %}
{% endfor %}

然后从 request.form 的每个命名字段中读取:

if form.validate_on_submit():
    db.session.query(Scores).delete()
    for option in all_options:
        for criterion in all_criteria:
            score_val = request.form.get(f'score_{option.id}_{criterion.id}', 0)
            db.session.add(Scores(option_id=option.id, criteria_id=criterion.id, scores=int(score_val)))
    db.session.commit()
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章