如何使用 Python、Flask 和 SQLite3 实现下拉 select 选项的动态依赖更改?

How do I implement dynamic dependent change of dropdown select options, using Python, Flask and SQLite3?

美好的一天。我真的是编程新手(3 个月),我正在尝试为我的课程期末项目添加最后一个功能。 在我的 html 页面中,我有 5 个 select 容器,第一个容器的数据来自我的 app.py 中的元组对象,其余 4 个选项数据来自 sqlite3 数据库查询。我希望这些选项相互依赖,无论用户首先 select 编辑哪个选项。 为了让您更多地了解我在说什么,所有选项都与武器类型相关(这是一个用于管理在线游戏库存的网络应用程序),此“类型”列存在于每个 table用于查询,远程武器表示为“1”,近战武器表示为“2”,两种类型均表示为“0”。 所以我是怎么理解的,我需要在一个选项被 selected 之后发出一个 json 请求,并且 return 将新的查询结果返回给 html 以便使用 javascript 处理新数据?但是接下来,当新选项将 selected 并减少变体时......我完全迷失在这里,因为我的 javascript 经验仅与 bootstrap (copy/paste )... 我希望我清楚地解释了一切,并且非常感谢一些如何做的例子。谢谢你的时间。

我的python代码:

@app.route("/add", methods=["GET", "POST"])
@login_required
def add():
    
    # assigning user_id to session
    user_id = session["user_id"]
    
    # this will be used for future dynamic change feature
    weapon_type = ("-1", "1")
    
    if request.method == "POST":
        
        # assigning user's input
        wtype = request.form.get("wtype")
        wname = request.form.get("wname")
        main_p = request.form.get("main_p")
        major_p = request.form.get("major_p")
        minor_p = request.form.get("minor_p")
        
        # check if input fields are blank or not valid
        if not wtype or wtype not in weapon_type:
            return apology("Invalid type")
        if not wname:
            return apology("Invalid type")
        if not main_p:
            return apology("Invalid type")

        # adding new weapon into users_weapons table
        db.execute("INSERT INTO user_weapons (user_id, weapon_id, main_id, major_id, minor_id) VALUES(?, ?, ?, ?, ?)", user_id, wname, main_p, major_p, minor_p)
        
        return redirect("/inventory")
    
    else:
        
        # adding options for select forms
        weapons = db.execute("SELECT id, name FROM weapons")
        mains = db.execute("SELECT id, name FROM mainp")
        majors = db.execute("SELECT id, description FROM majorp")
        minors = db.execute("SELECT id, description FROM minorp")
        
        return render_template("add.html", weapons=weapons, mains=mains, majors=majors, minors=minors)

我的html代码:

{% block main %}
    <form action="/add" method="post">
        <div class="form-group">
            <select class="form-control col-md-4 bg-dark text-success" name="wtype">
                <option disabled selected>Weapon Type</option>
                <option value="-1">Melee</option>
                <option value="1">Ranged</option>
            </select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="wname">
                <option disabled selected>Weapon Name</option>
                {% for weapon in weapons %}
                    <option value="{{ weapon["id"] }}"> {{ weapon["name"] }} </option>
                {% endfor %}
            </select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="main_p">
                <option disabled selected>Main Prefix *</option>
                {% for main in mains %}
                    <option value="{{ main["id"] }}"> {{ main["name"] }} </option>
                {% endfor %}
            </select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="major_p">
                <option disabled selected>Major Prefix **</option>
                {% for major in majors %}
                    <option value="{{ major["id"] }}"> {{ major["description"] }} </option>
                {% endfor %}
            </select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="minor_p">
                <option disabled selected>Minor Prefix ***</option>
                {% for minor in minors %}
                    <option value="{{ minor["id"] }}"> {{ minor["description"] }} </option>
                {% endfor %}
            </select>
        </div>
        <br>
        <button class="btn btn-outline-dark btn-lg" type="submit">Add Item</button>
    </form>
{% endblock %}

因此,在我朋友 (向 Scraelos 大声疾呼!:) 的帮助下,我们能够使用 Flask 的 Jsonify 功能解决这个问题,并且 Jquery。这与我最初想要实现的方法略有不同,但它更适合我的网络应用程序的一般用途。

(通过这样做,我能够消除通过“/add”路由的 GET 方法填充 select 选项的需要)

python代码:

@app.route("/options")
@login_required
def options():
    
    wtype = request.args.get('wtype')
    
    weapons = db.execute("SELECT id, name FROM weapons WHERE type = ?", wtype)
    mains = db.execute("SELECT id, name FROM mainp WHERE type = ? OR type = 0", wtype)
    majors = db.execute("SELECT id, description FROM majorp WHERE type = ? OR type = 0", wtype)
    minors = db.execute("SELECT id, description FROM minorp WHERE type = ? OR type = 0", wtype)
    
    return jsonify(weapons=weapons, mains=mains, majors=majors, minors=minors)

javascript代码:

$(document).ready(function() {

      // first we hide opions 2-5 and button
      $('#wname').hide();
      $('#main_p').hide();
      $('#major_p').hide();
      $('#minor_p').hide();
      $('#submitbtn').hide();

      // when 1st available option is changed, we get JSON from "/options"
      $('#wtype').change(function(){

        $.getJSON('/options', {
          wtype: $('#wtype').val()
        
        // if request successful process data
        }).done(function(data) {
              
              // remeber selected options for later use
              mainp=$('#main_p').val();
              majorp=$('#major_p').val();
              minorp=$('#minor_p').val();
              
              // empty options for now...
              $('#wname').empty();
              $('#main_p').empty();
              $('#major_p').empty();
              $('#minor_p').empty();
              
              // appending placeholder options
              $('#wname').append($('<option disabled selected>Weapon Name</option>'));
              $('#main_p').append($('<option disabled selected>Main Prefix &#9734</option>'));
              $('#major_p').append($('<option disabled selected>Major Prefix &#9734&#9734</option>'));
              $('#minor_p').append($('<option disabled selected>Minor Prefix &#9734&#9734&#9734</option>'));              
              
              // appending real options available for chosen type trough itteration
              $.each(data.weapons, function(key, val) {
                $('#wname').append($('<option>').text(val.name).attr('value', val.id));
              });
              $.each(data.mains, function(key, val) {
                $('#main_p').append($('<option>').text(val.name).attr('value', val.id));
              });
              $.each(data.majors, function(key, val) {
                $('#major_p').append($('<option>').text(val.description).attr('value', val.id));
              });
              $.each(data.minors, function(key, val) {
                $('#minor_p').append($('<option>').text(val.description).attr('value', val.id));
              });
              
              // after all new options were added to selection, this "if" condition checks if previously saved option is in new options list
              if ($("#main_p option[value="+mainp+"]").length > 0){
                // if true, select this option
                $('#main_p').val(mainp).change();
              }
              
              if ($("#major_p option[value="+majorp+"]").length > 0){
                $('#major_p').val(majorp).change();
              }
              
              if ($("#minor_p option[value="+minorp+"]").length > 0){
                $('#minor_p').val(minorp).change();
              }
              
              // make select options and button fadeIn from "hide"
              $('#wname').fadeIn();
              $('#main_p').fadeIn();
              $('#major_p').fadeIn();
              $('#minor_p').fadeIn();
              $('#submitbtn').fadeIn();
         })
      });
    });

和 HTML 毕竟看起来像这样:

{% extends "layout.html" %}

{% block title %}
    Add
{% endblock %}

{% block main %}
    <form action="/add" method="post">
        <div class="form-group">
            <select class="form-control col-md-4 bg-dark text-success" name="wtype" id="wtype">
                <option disabled selected>Weapon Type</option>
                <option value="-1">Melee</option>
                <option value="1">Ranged</option>
            </select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="wname" id="wname">
                
        <!--    I was able to remove below syntax, by performing table select population through Jquery code in fetch.js
                
                <option disabled selected>Weapon Name</option>
                {% for weapon in weapons %}
                    <option value="{{ weapon["id"] }}"> {{ weapon["name"] }} </option>
                {% endfor %}
                
        -->
            </select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="main_p" id="main_p"></select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="major_p" id="major_p"></select>
            <br>
            <br>
            <select class="form-control col-md-4 bg-dark text-success" name="minor_p" id="minor_p"></select>
        </div>
        <br>
        <button class="btn btn-outline-dark btn-lg" type="submit" id="submitbtn">Add Item</button>
    </form>
    <script src="/static/fetch.js"></script>
{% endblock %}

也许有人会发现此解决方案有用。和平! :)