简体   繁体   中英

How to get the selected value from html select tag using Flask

I know this question has been asked before but I have been through all the posts and none of the solutions seem to work for me.

Please bear with me. I am new to Flask and html and trying to build my first web app.

It's supposed to work as follows: The user uploads an Excel workbook and the workbook headers are displayed in a dropdown list using the html "select" tag. The user should then select one of the headers. I would then like to pass the selected header into a function.

I am able display the workbook headers in the dropdown list, but when I select a header, nothing happens. Does anyone have any idea what I'm doing wrong?

Please see python code below:

import flask
from flask import Flask
from flask import request
import pandas as pd

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def index():
    global headers_list
    headers_list=[]

    if request.method == "POST":
        df=request.files["file"]
        if df:
            df=pd.read_excel(df)
            headers_list=get_headers(df)
            selected_header = request.form.get("header")
            print(str(selected_header)) #to test the code
        else:
            print("No file selected")
    return (flask.render_template("./index.html", headers_list=headers_list))

def get_headers(dataframe):
    headers=list(dataframe.columns)
    return headers

if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8080, debug=True)

HTML below:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="description" content=""
        <title><Contra Tool</title>
        
    </head>

    <body>
        <h1>Contra Tool</h1>
        <p>Describe functionality</p>
        <br/>
    </body>

    <form action="" method="post" enctype=multipart/form-data>
        <label for ="myfile" > Select a file:</label>
        <input type="file" id="myfile" name="file" EnableViewState=True>
        <input type="submit" value="Upload">

    </form>

    <br><br>
    
    <div class="dropdown">
    <button class="dropbtn">Dropdown</button>
        <div>
            <form action="" method="POST">
                <SELECT class="dropdown-content" name="header" method="POST" action="/">
                    <ul>
                        <option value="{{headers_list[0]}}" selected>{{headers_list[0]}}</option>
                        {% for h in headers_list[1:]%}
                            <option value="{{h}}">{{h}}</option>
                        {% endfor %}
                    </ul>
                </SELECT>

            </form>

        </div>
    </div>
    
    <br/>
    <input type="submit">

</html>

Since I am assuming that you do not want to save the excel file on the server, in my opinion there remains a variant in which the file is transferred twice.
If the user selects a file, it is transferred in the background to query the header columns. The select element is filled with the information received.
From now on a column can be selected and the form can be transferred.

In my example there are two routes. One to display and process the form and another which on request returns the header columns in JSON format.

from flask import Flask 
from flask import abort, jsonify, render_template, request
import pandas as pd

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST' and 'file' in request.files:
        file = request.files['file']
        df = pd.read_excel(file)
        head = request.form.get('head');
        print(f'selected "{head}"')
    return render_template('index.html')

@app.route('/headers', methods=['POST'])
def headers():
    if 'file' in request.files:
        file = request.files['file']
        df = pd.read_excel(file)
        headers = list(df.columns)
        return jsonify(headers=headers)
    abort(400)

If the user selects a file, it is sent to the second route via AJAX. The select element is emptied and refilled and all necessary further elements are made available after the response from the server has been received. If the user presses submit, the completed form is sent with the file and the selected column.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <form method="POST" enctype="multipart/form-data">
      <input type="file" name="file" id="file" />
      <select name="head" id="head" disabled>
        <option>Choose Header</option>
      </select>
      <input type="submit" id="submit" disabled />
    </form>

    <script type="text/javascript">
      (() => {
        const fileElem = document.getElementById('file');
        fileElem.addEventListener('change', evt => {
          const formData = new FormData();
          formData.append('file', evt.target.files[0]);
          fetch('/headers', { method: 'POST', body: formData })
            .then(resp => resp.json())
            .then(data => {
              // clear select options
              const selectElem = document.getElementById('head');
              for (let i=selectElem.options.length-1; i >= 0; --i) {
                  selectElem.remove(i);
              }

              // populate select options
              const headers = data['headers'];
              for (const head of headers) {
                const optElem = document.createElement('option');
                optElem.value = head;
                optElem.innerHTML = head;
                selectElem.append(optElem);
              }
              selectElem.disabled = false;

              const elem = document.getElementById('submit');
              elem.disabled = false;
            });
        });
      })();
    </script>
  </body>
</html>

Remember, this is a minimal example and may need to be adapted and revised to meet your requirements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM