Flask / Python / WTForms validation and dynamically set SelectField choices

99封情书 提交于 2021-02-10 16:00:06

问题


I'm trying to create a simple Flask / Python one page web app that uses dynamically created choices for a SelectField.

However, I can't get it to POST using dynamically created choices, and there's also some funny validation behaviour going on (will explain after the code)

I created a minimum failing example here:

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()

Bringing up the page works just fine, and immediately flashes "nope", as expected.

Calculating the difference between the default set fields: -works every time as long they are both set to '0' -if either field is not set to '0', every other POST fails validation, and the time correctly calculates the difference and dynamically sets the last field.

Trying to POST using the dynamically set field fails every time.

Am I missing something very obvious here?

I'm rendering using this:

{% 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 %}

回答1:


It's failing every other time because the value of form.dynamic_field is oscillating between 0 and None. The form passes validation only when the value is None.

This is because form.dynamic_field.choices is [] (an empty list) at the time of validation. So any value that comes there is rejected. You probably want to dynamically set the choices before you try the validating; maybe with something like this:

@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)

Now the form will validate as expected.

Of course, you should probably add some code in front to make sure that the default_fields do have valid choices values (not just any two integers). Another option is to put dynamic_field in a second form. Then you can validate the first form, and use its values to calculate valid choices for the second one.



来源:https://stackoverflow.com/questions/42721564/flask-python-wtforms-validation-and-dynamically-set-selectfield-choices

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!