2

I am attempting to create a dynamic drop down (SelectField) with WTForms. I have read the documentation and have looked at quite a few answers on stack, and all of the examples involve iterating over a db query.

I simply want to iterate over a list (that's generated from an external API call) to inject the SelectField choices. For example:

class ToolForm(FlaskForm):


    myField3 = SelectField(u'Select Account', choices=[], coerce=int)


@app.route("/test", methods=['GET', 'POST'])
def test():
    form = ToolForm()
    accounts5 = []

    if request.method == 'POST':
        if request.form['submit_button'] == 'Select Account':

            #code that generates list called "accounts5"

            acctchoices = [(c.id,c.name) for c in accounts5]
            form.myField3.choices = acctchoices

    return render_template('test.html', title='test', form=form, accounts5=accounts5)

And my relevant HTML looks like:

<div class="form-group">
    {{ form.myField3.label(class="form-control-label") }} {% if form.myField3.errors %} {{ 
    form.myField3(class="form-control form-control-lg is-invalid") }}
    <div class="invalid-feedback">
        {% for errors in form.myField3.errors %}
        <span>{{ error }}</span>
        {% endfor %}
    </div>
    {% else %} {{ form.myField3(class="form-control form-control-lg") }} {% endif %}
</div>
<form action="http://127.0.0.1:5000/test" method="post">


    <input type="submit" class="btn btn-outline-info" name="submit_button" value="Select Account">

</form>

When I click "Select Account" I get an 'int' object has no attribute 'id' error. I thought this might be a data type issue so I tried with a list of strings but to no avail.

My question is, how can I populate my SelectField from a list?

3
  • What does accounts5 look like? Are you sure it comes with 'id' and 'name' that you can access? Commented Jan 16, 2020 at 6:02
  • @Till Accounts5 looks like a normal list, which I realize now was an oversight. I tried building a list with tuples like accounts5 = [("test", '1'), ("tested", '3'), ("testing", '3')] but got 'tuple' object has no attribute 'id' Commented Jan 16, 2020 at 21:47
  • 1
    Ok, in this list you've switched the ID and the Name for the SelectField. Why don't you try to simplify your logic first and get a SelectField working? If you set accounts5 = [('1', 'test'), ('3','tested'),('4','testing')] and form.myField3.choices = accounts5 then it will work. The list you're showing doesn't have an 'id' or 'name' attribute for a primary key (the database object you've taken the example from does though). Commented Jan 17, 2020 at 1:35

1 Answer 1

3

When you GET that route it will load a form that is generic and render it to the page, without any myField3 choices having been set or available.

You can control the form to load based on certain criteria by using the __init__ override:

class ToolForm(FlaskForm):
    myField3 = SelectField(u'Select Account', choices=[], coerce=int)
    def __init__(self, accounts=None):
        super().__init__()  # calls the base initialisation and then...
        if accounts: 
            self.myField3.choices = [(c.id, c.name) for c in accounts]

Then you will construct the form from some other information based on the route request:

   @app.route("/test", methods=['GET', 'POST'])
   def test():
       # define accounts
       form = ToolForm(accounts=accounts)     
Sign up to request clarification or add additional context in comments.

2 Comments

This was an interesting answer and gave me some new ideas, but I still get the same error 'int' object has no attribute 'id and when I changed it to a tuple I got 'tuple' object has no attribute 'id
As @Till says just use self.myField.choices = accounts. Only classes can identify attributes using a .. like c.id otherwise you index a tuple by index, i.e. c[0] and c[1]. This error is related to a separate problem of you not defining accounts correctly according to how you want to populate choices.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.