【问题标题】:How can I create a form from a list of models using WTForms?如何使用 WTForms 从模型列表中创建表单?
【发布时间】:2014-07-23 23:50:16
【问题描述】:

我有一个Prediction 模型列表。我想将它们绑定到一个表单并允许使用回发。如何构建我的表单,以便帖子将 Home/Away 分数与我绑定到表单的每个项目的 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>

我无法让我的数据在POST 上正确绑定。所需的验证器不断失败,因为发布数据缺少所有 必填 字段。

【问题讨论】:

  • 没问题。我真的不能再帮你了。这是一个工作要点gist.github.com/nsfyn55/039288a4c1a6dd6ca8ee。要么是您未包含某些内容,要么是印刷错误。
  • 我刚刚复制了你写的代码,我得到了
      也许它与版本有关?
    • 也许我更新了要点供您比较
    • 您是在运行我的要点python predictions.py 还是尝试将其集成到您的代码中。因为这就是我对你的理解,可能有一些印刷错误或其他不相关的问题。
    • 我刚刚复制了你的代码并在我的文本编辑器中运行它..sublime text2

    标签: python flask jinja2 wtforms flask-wtforms


    【解决方案1】:

    您需要一个绑定到预测列表中的项目的子表单:

    您描述的表格只允许您提交一个预测。似乎存在差异,因为您绑定了一个可迭代的预测,并且您似乎希望每个预测都有一个主场和客场预测。事实上,它永远不会回发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>
    

    现在这将打印一个 &lt;ul&gt; 和一个 &lt;li&gt; 每个项目,因为这就是 FieldList 所做的。我将把它留给你来设置它的样式并将它变成表格形式。这可能有点棘手,但并非不可能。

    在 POST a 中,您将获得一个 formdata 字典,其中包含每个预测的 id 的主客场得分。然后,您可以将这些预测绑定回您的 SQLAlchemy 模型。

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

    【讨论】:

    • 我收到此错误:UndefinedError: 'wtforms.ext.csrf.fields.CSRFTokenField object' has no attribute 'predictions'。在我看来,我的预测代码是: predictions = Fixture_prediction.query.join(Fixture)\ .outerjoin(User,Fixture_prediction.user_id == User.id)\ .filter(Fixture_prediction.fixture_id==Fixture.id)\ .filter (Fixture_prediction.user_id==user_id).all()
    • 看起来它无法找到预测()
    • 你需要一个for循环来覆盖预测吗?
    • 我添加了 hidden_tag 字段,如果您在 Flask 中有 CSRF_ENABLED,这是必需的。此答案假定您的模型查询有效并返回至少具有 id 字段的 Prediction 模型列表。如果该查询不起作用,则超出此问题的范围。还要记住在您的render_template 方法中form 必须等于PredictionListForm 的实例而不是PredictionForm
    • 您不需要循环 FieldList 遍历每个项目并为每个项目呈现一个 &lt;li&gt;
    【解决方案2】:
     {% 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 不错,每个按钮的名字和触发功能都很难得到。

    【讨论】:

      【解决方案3】:
      from wtforms import fields
      from wtforms.fields import FieldList, FormField
      from wtforms import validators
      

      一些提示,可能会添加一些导入并清除导入错误消息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-28
        • 2018-03-18
        • 1970-01-01
        • 2013-09-25
        • 1970-01-01
        • 2020-07-18
        • 2015-01-05
        相关资源
        最近更新 更多