问题
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_field
s 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