3

similar to this question: Dynamic choices WTForms Flask SelectField

In my flask app I have a WTForm with several selectfields. I would like to dynamically assign the number of the selectfields and the choices of the selectfields.

class FormEntry(FlaskForm):
        selectfield = SelectField('Name', coerce=int, choices=[('1', 'default_choice1'), ('2', 'default_choice2')])


class MyForm(FlaskForm):
    form_entries = FieldList(FormField(FormEntry), min_entries=1)

An instance of a FormEntry is created and the choices are assigned:

my_entry = FormEntry()
my_entry.selectfield.choices =[('3', 'mychoice3'), ('4', 'mychoice4')]

However, when I create an instance of the Form with this entry, the choices are not my chosen choices but the default ones:

form_entries = [my_entry, my_entry]
form = MyForm(form_entries=form_entries)
for entry in form.form_entries:
    print(entry.selectfield.choices)

Print Output:

[('1', 'default_choice1'), ('2', 'default_choice2')]
[('1', 'default_choice1'), ('2', 'default_choice2')]

What went wrong and how can I assign the choices correctly?

otwtm
  • 1,779
  • 1
  • 16
  • 27
  • 2
    The suggested duplicate question is incorrect; it is not a duplicate. I also had this issue and found this post useful. – Gman Feb 06 '20 at 22:25

1 Answers1

2

https://wtforms.readthedocs.io/en/stable/fields.html#wtforms.fields.SelectField

From the documentation (emphasis mine)

Note that the choices keyword is only evaluated once, so if you want to make a dynamic drop-down list, you’ll want to assign the choices list to the field after instantiation. Any inputted choices which are not in the given choices list will cause validation on the field to fail.

i.e don't have selectfield = SelectField('Name', coerce=int, choices=[('1', 'default_choice1'), ('2', 'default_choice2')] use selectfield = SelectField('Name', coerce=int) instead.

Andrew Allen
  • 6,512
  • 5
  • 30
  • 73
  • 1
    Thanks. But If I don't provide default values for the choices, I get "TypeError: 'NoneType' object is not iterable". – otwtm May 18 '19 at 13:33
  • Are you still setting the choices via `.choices` or how though davidism suggests in his link to his own answer (though before `validate_on_submit`)? – Andrew Allen May 18 '19 at 14:00
  • So far, still setting the choices via '.choices'. If I then remove the default choices in the constructor, the above print output becomes : None, None. – otwtm May 18 '19 at 14:11
  • a few posts on SO I've seen suggest doing `form = MyForm()` then `form.form_entries[0].selectfield.choices = whatever` – Andrew Allen May 18 '19 at 14:28
  • 2
    What worked for me in the end is very similar to your last comment: `form = MyForm({})` then `form.form_entries[0].selectfield.choices = whatever`. So I accept the answer. Thanks for your help. – otwtm May 19 '19 at 20:02
  • 1
    However, I still do not understand why the code in my question does not work. – otwtm May 19 '19 at 20:03