I'm dynamically populating a form in Flask using a FormList of FormFields but am at a loss with an error from the validation function. On this form, the user provides an entry name and then for each game queried from a database table, picks one from a RadioField and ranks their confidence in their pick 1-N. I've tested the validation with a test that was hard-coded, and I've gotten the dynamic field generation below to work, but when I try to validate the below it fails when iterating through games-#-pick with 'NoneType' is not iterable.
I believe this is because the loop keeps going beyond my bounds. In my test I only have three entries in games, so idx is 0,1,2 and I should see three PickForms generated. When validate fails I see self.name is games-3-pick, so validate is checking one more FormField in my FormList than I though should have been generated.
How do I validate this? Is it an issue with the FormField validation, or how I'm dynamically appending_entry() to the FormList?
@bp.route('/pick', methods=['GET', 'POST'])
def pick():
games = Game.query.order_by(Game.game_date.asc()).all()
form = EntryForm()
for idx, g in enumerate(games):
form.games.append_entry()
form.games[idx].pick.label = g.bowl_name
form.games[idx].pick.choices = [('away', g.away), ('home', g.home)]
if form.validate_on_submit():
...database writes and redirect if validated...
class PickForm(FlaskForm):
pick = RadioField(validators=[DataRequired()])
weight = IntegerField('Weight', validators=[DataRequired()])
class EntryForm(FlaskForm):
name = StringField('Entry Name', validators=[DataRequired()])
games = FieldList(FormField(PickForm))
submit = SubmitField('Submit')
def validate(self):
if not super(EntryForm, self).validate():
return False
result = True
seen = set()
for pick in self.games:
if (pick.weight.data in seen and
pick.weight.data <= len(self.games)):
pick.errors.append('Please rank reach pick from 1 to {} with no repeats.'.format(len(self.games)))
result = False
else:
seen.add(pick.weight.data)
return result
The issue ended up being I was appending entries onto
form.gameson both the GET and POST requests, resulting in a list twice the size I wanted with the top half not populated. A little more logic to check the current length ofform.gamesbefore appending an entry got around this. This may not be the most elegant possible way of dynamically adding these fields, but it works for now and is a lot better than the previous way I was doing it!