烧瓶中 html 的动态下拉列表

问题描述 投票:0回答:1

我正在尝试构建一个简单的 Flask 应用程序,用户可以在其中上传 CSV 文件。通过相同表单的下拉列表,用户应该能够选择一列。现在,我需要根据上传的 CSV 标头填充此下拉列表。查看了各种解决方案。尝试了一些被标记为正确的。然而,要么我收到错误“Nonetype object not iterable”,要么列未填充。

我不能使用 json.

根据某人在不同查询中发布的答案,我的代码是 -

在 app.py 中:

@app.route('/upload', methods=['GET', 'POST'])
def upload():
    col_names = request.args.get('col_names')
    if request.method == 'POST':
        file = request.files.get('file')
        if file and file.filename.endswith('.csv'):
            df = pd.read_csv(file)
            col1 = request.form.get('col1')
            col2 = request.form.get('col2')
            col3 = request.form.get('col3')
            return render_template('upload.html', col_names=col_names,
                                   col1=col1, col2=col2, col3=col3)
        else:
            return 'Invalid file format'
    else:
        return render_template('upload.html', col_names=col_names)

在upload.html中:

<form action="/upload?col_names={{ col_names }}" method="POST" enctype="multipart/form-data">
    <label for="file">File:</label>
    <input type="file" id="file" name="file"><br />
    <label for="col1">Column 1:</label>
    <select id="col1" name="col1">
        {% for col in col_names %}
        <option value="{{ col }}">{{ col }}</option>
        {% endfor %}
    </select>
    <br />
    <label for="col2">Column 2:</label>
    <select id="col2" name="col2">
        {% for col in col_names %}
        <option value="{{ col }}">{{ col }}</option>
        {% endfor %}
    </select>
    <br />
    <label for="col3">Column 3:</label>
    <select id="col3" name="col3">
        {% for col in col_names %}
        <option value="{{ col }}">{{ col }}</option>
        {% endfor %}
    </select>
    <br />
    <button>Upload</button>
</form>

我如何填充这些下拉菜单?

python html flask dynamic dropdown
1个回答
0
投票

我的建议是选择后立即在后台使用javascript上传文件。现在可以提取文件的列并使用返回的部分提供选择。如果最终发送了表单,您将收到文件和选定的列并可以处理它们。

烧瓶 (./app.py)
from flask import (
    Flask, 
    abort, 
    render_template,
    request 
)
import pandas as pd

app = Flask(__name__)

@app.route('/csv-upload', methods=['GET', 'POST'])
def csv_upload():
    if request.method == 'POST':
        file = request.files.get('file')
        cols = request.form.getlist('column')
        if file and file.filename.endswith('.csv') and len(cols) == 3:
            df = pd.read_csv(file)
            if len(df.columns) >= 3 and all(c in df.columns and cols.count(c) == 1 for c in cols): 
                print(df)
                print(cols)
    return render_template('csv_upload.html')

@app.post('/csv-columns')
def csv_columns():
    file = request.files.get('file')
    if file and file.filename.endswith('.csv'):
        df = pd.read_csv(file)
        if len(df.columns) >= 3: 
            columns = df.columns
            return render_template('csv_columns.html', **locals())
    abort(400)
HTML (./templates/csv_upload.html)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Upload</title>
    <style type="text/css">
        fieldset[disabled] {
            display: none;
        }
    </style>
</head>
<body>
    <form method="POST" enctype="multipart/form-data">
        <fieldset name="file">
            <div>
                <label for="file">File:</label>
                <input type="file" name="file" id="file" accept="text/csv" />
            </div>
        </fieldset>
        
        <fieldset name="columns" disabled>
        </fieldset>

        <button type="submit" disabled>Upload</button>
    </form>

    <script type="text/javascript">
        (function() {
            const fieldsetElem = document.querySelector('fieldset[name="columns"]');
            const fileElem = document.querySelector('input[name="file"]');
            const btnElem = document.querySelector('button[type="submit"]');

            fileElem.addEventListener('change', async function(event) {
                btnElem.disabled = true;
                fieldsetElem.disabled = true;

                const data = await fetch('/csv-columns', {
                    method: 'POST', 
                    body: new FormData(this.form)
                }).then(resp => resp.ok && resp.text());

                if (data) {
                    fieldsetElem.innerHTML = data;

                    const selElems = Array.from(fieldsetElem.querySelectorAll('select[name="column"]'));
                    selElems.forEach(elem => {
                        elem.addEventListener('change', () => {
                            btnElem.disabled = !(selElems.every(e => e.value != '') 
                                && (new Set(Array.from(selElems, e => e.value))).size === selElems.length);
                        })
                    });

                    fieldsetElem.disabled = false;
                } else {
                    console.error('Something went wrong.')
                }

            });

        })();
    </script>
</body>
</html>
HTML (./templates/csv_columns.html)
{% for i in range(3) -%}
    <div>
        <label for="column-{{i}}">Column {{i+1}}</label>
        <select name="column" id="column-{{i}}">
            <option value selected>-- Select a column --</option>
            {% for col in columns -%}
            <option value="{{ col }}">{{ col }}</option>
            {% endfor -%}
        </select>
    </div>
{% endfor -%}
© www.soinside.com 2019 - 2024. All rights reserved.