'Using <input> inside for loop in jinja flask

I am struggling to figure out how to access individual <input> elements, that have been created through a for loop. For example:

<form id="score" method="POST" action="/div">
    <div class="formInput">
        {% for i in range(2) %}
            <input type="text" class="sFixed" id="scoreFixed">
        {% endfor %}
    </div>
</form>

As you can see, I'm creating two input element's in my form. However, if I try to retrieve the data that I have entered through my Python Flask application, I am only able to get the first input, not the second. Here is how I am trying to retrieve the data.

@app.route('/div', methods=['POST'])
def div_post():
    scoreFixed = request.form.get('scoreGame')
    print(scoreFixed)

    return redirect('/')

Please help me figure out how to retrieve the input from both elements that have been created in the form.



Solution 1:[1]

Every id can only exist once in a html document or form. You can set unique ids by using the for loop index in your template. Also you need to give each input a unique name

{% for i in range(2) %}
    <input 
        type="text" 
        class="sFixed" 
        id="scoreFixed_{{i}}" 
        name="scoreFixed_{{i}}">
{% endfor %}

In your flask endpoint you can then access the scores like this

scores = []
for i in range(2):
    score = request.form.get(f"scoreFixed_{i}")
    scores.append(score)   

Solution 2:[2]

First:

You have to use name= instead of id= to get it in Flask.

I tested it on Python 3.8, Flask 1.1.4 and 2.0.3, Linux Mint 20, browsers Firefox, Chrome, Edge.

In other frameworks/languages you also have to use name= instead of id= because browsers send name but not id.

Second:

You can use getlist("scoreFixed") to get list with all elements with the same name.

Of course you can use {{ i }} to add number to name to get every value separatelly

{% for i in range(2) %}
    <input type="text" name="scoreFixed_{{ i }}" ></br>
{% endfor %}

Third:

You need button to send it.


Minimal working example:

from flask import Flask, request, render_template_string

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    print('args :', request.args)
    print('form :', request.form)
    print('json :', request.json)
    print('files:', request.files)

    print('scoreFixed getlist():', request.form.getlist("scoreFixed"))
    print('scoreFixed     get():', request.form.get("scoreFixed"))
    
    print('scoreFixed_0 getlist():', request.form.getlist("scoreFixed_0"))
    print('scoreFixed_0     get():', request.form.get("scoreFixed_0"))
    
    print('scoreFixed_1 getlist():', request.form.getlist("scoreFixed_1"))
    print('scoreFixed_1     get():', request.form.get("scoreFixed_1"))


    return render_template_string('''<form method="POST">

    {% for i in range(2) %}
        <input type="text" name="scoreFixed" > scoreFixed</br>
    {% endfor %}

    {% for i in range(2) %}
        <input type="text" name="scoreFixed_{{ i }}" > scoreFixed_{{ i }}</br>
    {% endfor %}
<button type="submit">SEND</button>
</form>''')

if __name__ == '__main__':
    #app.debug = True 
    app.run()

enter image description here

Result for values a, b, c, d

args : ImmutableMultiDict([])
form : ImmutableMultiDict([('scoreFixed', 'a'), ('scoreFixed', 'b'),
          ('scoreFixed_0', 'c'), ('scoreFixed_1', 'd')])
json : None
files: ImmutableMultiDict([])

scoreFixed getlist(): ['a', 'b']
scoreFixed     get(): a

scoreFixed_0 getlist(): ['c']
scoreFixed_0     get(): c

scoreFixed_1 getlist(): ['d']
scoreFixed_1     get(): d

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2