Flask/Python/WTForms验证和动态设置SelectField选项

Flask/Python/WTForms验证和动态设置SelectField选项,python,flask,wtforms,Python,Flask,Wtforms,我正在尝试创建一个简单的Flask/Python单页web应用程序,它为SelectField使用动态创建的选项 但是,我无法使用动态创建的选项将其发布,而且还有一些有趣的验证行为(将在代码后解释) 我在这里创建了一个最小失败示例: from flask import Flask, render_template, flash, redirect from flask_wtf import Form from wtforms import IntegerField, SubmitField, S

我正在尝试创建一个简单的
Flask
/
Python
单页web应用程序,它为SelectField使用动态创建的选项

但是,我无法使用动态创建的选项将其发布,而且还有一些有趣的验证行为(将在代码后解释)

我在这里创建了一个最小失败示例:

from flask import Flask, render_template, flash, redirect
from flask_wtf import Form
from wtforms import IntegerField, SubmitField, SelectField
from wtforms.validators import DataRequired, NumberRange, Optional

# Set up app and config    
DEBUG = True
SECRET_KEY = '42721564'
app = Flask(__name__)
app.config.from_object(__name__)

# Main stuff starts here

class SelectFieldForm(Form):
    default_field = SelectField('Default Set SelectField', choices=[(i, i) for i in range(0,60,5)], coerce=int)
    default_field_2 = SelectField('Default Set SelectField', choices=[(i, i) for i in range(0,60,5)], coerce=int)
    dynamic_field = SelectField('Dynamically Set Selectfield', choices=[], validators=[Optional()], coerce=int)

    get_default_field_value_difference = SubmitField(label='Get Default Field Difference')
    deduct_dynamic_field_value = SubmitField(label='Deduct Dynamic Field Value')


@app.route('/mfe-dynamic-selectfield', methods=['GET', 'POST'])
def failingSelectField():
    form = SelectFieldForm()

    if form.validate_on_submit():
        print("validated")

        difference = form.default_field_2.data - form.default_field.data

        if form.get_default_field_value_difference.data:
            flash( difference )
            form.dynamic_field.choices = [(i,i) for i in range(0,difference,5)]

            return render_template('mfe-dynamic-selectfield.html', form=form)

        if form.deduct_dynamic_field_value.data:

            if form.dynamic_field.data:
                deducted = difference - form.dynamic_field.data
                flash( deducted )

            else:
                flash( "no dynamic field value chosen")           

            return render_template('mfe-dynamic-selectfield.html', form=form)

        else:
            flash( "nope" )

    return render_template('mfe-dynamic-selectfield.html', form=form)

if __name__ == '__main__':
    app.run()
打开页面效果很好,并如预期的那样立即闪烁“否”

计算默认设置字段之间的差异: -只要它们都设置为“0”,每次都有效 -如果任一字段未设置为“0”,则每隔一次POST验证都会失败,时间会正确计算差异并动态设置最后一个字段

每次尝试使用动态设置字段进行POST都会失败

我是不是错过了一些很明显的东西

我正在使用以下方式渲染:

{% block content %}
<form action="" method="post" name="mfe-dynamic-selectfield">
  {{ form.hidden_tag() }}
  <table>
  <tr>
      <td> Calculated value </td>
      <td>

      {% with messages = get_flashed_messages() %}
          {% if messages %}
            <ul class=flashes>
            {% for message in messages %}
              <li>{{ message }}</li>
            {% endfor %}
            </ul>
          {% endif %}
       {% endwith %}

       </td>
  </tr>

  <br>
  <tr>
      <td>Default SelectField 1</td>
      <td>Default SelectField 2</td>

      <td>Dynamic Selectfield</td>
  </tr>

  <br>

  <tr>
      <td>{{ form.default_field }}</td>
      <td>{{ form.default_field_2 }}</td>

      <td>{{ form.dynamic_field }}</td>
  </tr>

  <tr>
      <td>{{ form.get_default_field_value_difference }}</td>
      <td>{{ form.deduct_dynamic_field_value }}</td>
  </tr>      

  </table>
</form>
{% endblock %}
{%block content%}
{{form.hidden_tag()}}
计算值
{%with messages=get_flashed_messages()%}
{%if消息%}

{消息%中的消息为%s}
  • {{message}}
  • {%endfor%} {%endif%} {%endwith%}
    默认选择字段1 默认选择字段2 动态选择字段
    {{form.default_field}} {{form.default_field_2}} {{form.dynamic_field}} {{form.get_default_field_value_difference}} {{form.deletry_dynamic_field_value}} {%endblock%}
    它每隔一次就会失败,因为
    表单的值。dynamic_字段
    0
    None
    之间振荡。只有当值为
    None
    时,表单才通过验证

    这是因为在验证时,
    form.dynamic_field.choices
    []
    (一个空列表)。因此,任何出现的值都会被拒绝。您可能希望在尝试验证之前动态设置选项;也许是这样的:

    @app.route('/mfe-dynamic-selectfield', methods=['GET', 'POST'])
    def failingSelectField():
        form = SelectFieldForm()
    
        # Calculate dynamic field choices
        try:
            difference = form.default_field_2.data - form.default_field.data
            form.dynamic_field.choices = [(i,i) for i in range(0,difference,5)]
        except TypeError:
            pass
    
        if form.validate_on_submit():
            # (continue as usual)
    
    现在表单将按预期进行验证


    当然,您可能应该在前面添加一些代码,以确保
    default\u字段
    s具有有效的选项值(而不仅仅是任意两个整数)。另一种选择是将
    动态_字段
    放入第二种形式。然后,您可以验证第一个表单,并使用其值计算第二个表单的有效选项。

    谢谢,这就像一个符咒。因此,在我对验证工作原理了解有限的情况下,这基本上是检查静态字段并设置动态字段,然后在每个POST/GET上验证表单。以前,在一篇文章中,我会将动态字段的值传递回去并重新呈现表单,但是在尝试验证之前,它不会设置在新表单上,所以失败了。。。?这仍然是我不太了解的部分。在尝试验证表单之前,您必须指定有效选项。它不会“记住”您上次设置的选项,因为每次加载/提交页面时,您都从一个新的
    SelectFieldForm
    开始。查看表单和验证的介绍。我想我明白了。文档并没有真正涵盖这个案例,但让我看看是否可以用逻辑的方式解释我是如何理解它的。
    try:
    部分在新的
    SelectFieldForm
    上设置有效选项,因为否则我们将尝试提交,验证没有有效选项。我想将应用程序保持在一个页面上,有没有一种不那么笨重的方式——也许不是每次加载/提交页面时都以新表单开始?