如何使用WTForms从模型列表创建表单?

4 投票
3 回答
4399 浏览
提问于 2025-04-18 08:25

我有一系列的 Prediction 模型。我想把它们绑定到一个表单上,并允许用户提交数据。请问我该如何设计这个表单,以便在提交时能把主场/客场的得分和每个 Prediction 模型的 id 字段关联起来呢?

视图

@app.route('/predictor/',methods=['GET','POST'])
@login_required
def predictions():    
    user_id = g.user.id
    prediction= # retrieve prediction
    if request.method == 'POST':
        if form.validate() == False:
            flash('A score is missing, please fill in all predictions')
            render_template('predictor.html', prediction=prediction, form=form)
        else:
            for pred in prediction:
                # store my prediction
            flash('Prediction added')
            return redirect(url_for("predictions"))    
    # display current predictions
    elif request.method == 'GET':
        return render_template('predictor.html', prediction=prediction, form=form)

表单

class PredictionForm(WTForm):
    id = fields.IntegerField(validators=[validators.required()], widget=HiddenInput())
    home_score = fields.TextField(validators=[validators.required()])
    away_score = fields.TextField(validators=[validators.required()])

模板

  <form action="" method="post">
    {{form.hidden_tag()}}
    <table>
        {% for pred in prediction %}
        <tr>
            <td>{{pred.id}}</td>
            <td>{{form.home_score(size=1)}}</td>
            <td>{{form.away_score(size=1)}}</td>               
        </tr>
        {% endfor %}
    </table>
    <p><input type="submit" value="Submit Predictions"></p>
   </form>

我在提交数据时无法正确绑定我的数据。因为提交的数据缺少所有的 必填 字段,所以验证器总是失败。

3 个回答

-3
from wtforms import fields
from wtforms.fields import FieldList, FormField
from wtforms import validators

一些小建议,可能需要添加一些导入内容,并清理导入时出现的错误信息。

0
 {% for key in di_RAA %}
   <tr>
   <td><form id="Run" action="{{ url_for('index') }}" method="post">
        <input type="submit" class="btn" value="TEST" name="RUN_{{key}}"> 
   </form></td>
   </tr>
 {% endfor %}

它提供了其他简单的方法来处理多个按钮。FieldList很好,但要获取每个按钮的名称和触发的功能有点困难。

8

你需要一个子表单,用来绑定预测列表中的项目:

你描述的这个表单只能提交一个单独的预测。这里似乎有点矛盾,因为你绑定了一个可迭代的预测列表,而看起来你想为每个预测提供主场和客场的结果。实际上,按照现在的方式,它永远不会提交一个 id 字段。这将导致你在表单验证时总是失败。我认为你想要的是一个子表单的列表。像这样:

# Flask's form inherits from wtforms.ext.SecureForm by default
# this is the WTForm base form. 
from wtforms import Form as WTForm

# Never render this form publicly because it won't have a csrf_token
class PredictionForm(WTForm):
    id = fields.IntegerField(validators=[validators.required()], widget=HiddenInput())
    home_score = fields.TextField(validators=[validators.required()])
    away_score = fields.TextField(validators=[validators.required()])

class PredictionListForm(Form):
    predictions = FieldList(FormField(PredictionForm))

你的视图需要返回类似于以下内容:

predictions = # get your iterable of predictions from the database
from werkzeug.datastructures import MultiDict
data = {'predictions': predictions}
form = PredictionListForm(data=MultiDict(data))
    
return render_template('predictor.html', form=form)

你的表单需要改成更像这样的形式:

<form action='my-action' method='post'>
    {{ form.hidden_tag() }}
    {{ form.predictions() }}
</form>

现在,这样会打印一个 <ul>,每个项目都有一个 <li>,因为这就是 FieldList 的作用。我留给你去美化它,并把它整理成表格形式。可能会有点棘手,但并不是不可能。

在提交表单时,你会得到一个包含每个预测的 id 的表单数据字典,其中包括主场和客场的得分。然后你可以将这些预测绑定回你的 SQLAlchemy 模型中。

[{'id': 1, 'home': 7, 'away': 2}, {'id': 2, 'home': 3, 'away': 12}]

撰写回答