You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask+MySQL二级联动下拉框实现:基于前置选项取值的技术指导

实现Flask中基于第一个下拉框选中值动态加载第二个下拉框选项

Hey there! Congrats on getting your first dropdown working with Flask and MySQL—great start. Let's walk through how to add the dynamic second dropdown based on the selected customer, plus key checks for your code.

第一步:后端添加过滤查询的API路由

首先,你已经有了获取所有客户名称的接口,现在需要新增一个接口,接收选中的客户名称,返回对应的实例列表。这里一定要用参数化查询来避免SQL注入,这是关键!

假设你的数据库中有一张表(比如叫instances),包含customer_name和instance_name字段。下面是示例代码:

from flask import Flask, jsonify, render_template
import mysql.connector

app = Flask(__name__)

# 现有获取客户列表的路由(你已经实现的部分)
@app.route('/get_customers', methods=['GET'])
def get_customers():
    # 替换成你的数据库连接信息
    db_config = {
        'host': 'localhost',
        'user': 'your_username',
        'password': 'your_password',
        'database': 'your_database'
    }
    conn = mysql.connector.connect(**db_config)
    cursor = conn.cursor()
    # 查询去重的客户名称
    cursor.execute("SELECT DISTINCT customer_name FROM instances")
    customers = [row[0] for row in cursor.fetchall()]
    conn.close()
    return jsonify(customers)

# 新增:根据选中的客户获取对应实例的路由
@app.route('/get_instances/<selected_customer>', methods=['GET'])
def get_instances(selected_customer):
    db_config = {
        'host': 'localhost',
        'user': 'your_username',
        'password': 'your_password',
        'database': 'your_database'
    }
    conn = mysql.connector.connect(**db_config)
    cursor = conn.cursor()
    # 这里用参数化查询(%s)来过滤,绝对不要直接拼接字符串!
    cursor.execute(
        "SELECT DISTINCT instance_name FROM instances WHERE customer_name = %s",
        (selected_customer,)
    )
    instances = [row[0] for row in cursor.fetchall()]
    conn.close()
    return jsonify(instances)

# 如果是用Jinja2渲染首页,添加这个路由
@app.route('/')
def index():
    # 这里可以复用get_customers里的逻辑获取客户列表,传给模板
    db_config = {
        'host': 'localhost',
        'user': 'your_username',
        'password': 'your_password',
        'database': 'your_database'
    }
    conn = mysql.connector.connect(**db_config)
    cursor = conn.cursor()
    cursor.execute("SELECT DISTINCT customer_name FROM instances")
    customers = [row[0] for row in cursor.fetchall()]
    conn.close()
    return render_template('index.html', customers=customers)

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

第二步:前端实现动态加载逻辑

接下来,在你的HTML模板里添加两个下拉框,并用JavaScript监听第一个下拉框的变化,实时请求后端获取对应实例:

示例HTML(index.html)

<!DOCTYPE html>
<html>
<head>
    <title>Dynamic Dropdowns</title>
</head>
<body>
    <h3>Select Customer & Instance</h3>
    <!-- 第一个下拉框:客户名称 -->
    <select id="customerSelect">
        <option value="">请选择客户</option>
        <!-- 如果用Jinja2渲染,取消下面注释并删除AJAX加载客户的代码 -->
        {% for customer in customers %}
            <option value="{{ customer }}">{{ customer }}</option>
        {% endfor %}
    </select>

    <!-- 第二个下拉框:实例名称 -->
    <select id="instanceSelect">
        <option value="">请先选择客户</option>
    </select>

    <script>
        // 如果不用Jinja2渲染客户列表,用这段代码加载第一个下拉框
        /*
        window.onload = function() {
            fetch('/get_customers')
                .then(res => res.json())
                .then(customers => {
                    const select = document.getElementById('customerSelect');
                    customers.forEach(cust => {
                        const option = document.createElement('option');
                        option.value = cust;
                        option.textContent = cust;
                        select.appendChild(option);
                    });
                });
        };
        */

        // 监听客户选择变化,动态加载实例
        document.getElementById('customerSelect').addEventListener('change', function() {
            const selectedCustomer = this.value;
            const instanceSelect = document.getElementById('instanceSelect');
            
            // 清空并显示加载状态
            instanceSelect.innerHTML = '<option value="">加载中...</option>';

            if (selectedCustomer) {
                // 请求后端获取对应实例
                fetch(`/get_instances/${selectedCustomer}`)
                    .then(res => res.json())
                    .then(instances => {
                        instanceSelect.innerHTML = '<option value="">请选择实例</option>';
                        instances.forEach(inst => {
                            const option = document.createElement('option');
                            option.value = inst;
                            option.textContent = inst;
                            instanceSelect.appendChild(option);
                        });
                    })
                    .catch(err => {
                        instanceSelect.innerHTML = '<option value="">加载失败,请重试</option>';
                        console.error('加载实例出错:', err);
                    });
            } else {
                // 未选择客户时重置下拉框
                instanceSelect.innerHTML = '<option value="">请先选择客户</option>';
            }
        });
    </script>
</body>
</html>

关键检查点

  • SQL注入防护:一定要用%s参数化查询,绝对不要直接把用户输入拼接到SQL语句里(比如"SELECT ... WHERE customer_name = '" + selectedCustomer + "'"),这会导致严重的安全问题。
  • 数据库连接:确认你的数据库主机、用户名、密码、数据库名称都正确,并且Flask应用有访问数据库的权限。
  • 路由匹配:前端fetch的URL要和后端路由完全一致,比如/get_instances/xxx对应@app.route('/get_instances/<selected_customer>')。
  • 表结构适配:如果你的客户和实例分存在不同表(比如customers和instances通过外键关联),需要调整SQL语句,比如:
    SELECT DISTINCT i.instance_name 
    FROM instances i 
    JOIN customers c ON i.customer_id = c.id 
    WHERE c.customer_name = %s
    
  • 前端元素ID:确保JS里的customerSelect和instanceSelect和HTML中下拉框的id完全一致。

内容的提问来源于stack exchange,提问作者S. G.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:54:31