如何使用 Flask 创建两个依赖的动态下拉列表

Ram*_*iro 2 javascript python jquery flask flask-sqlalchemy

我在 Flask 中修改了以下示例代码https://tutorial101.blogspot.com/2021/01/python-flask-dynamic-loading-of.html以使用 SQlite 数据库。app.py 的目标是显示汽车品牌的选项,然后按品牌显示可用的车型。app.py 使用两个下拉框,用户可以从中进行选择。原始源代码是用 Flask 编写的,用于访问 MySQL 数据库。我修改了 app.py 的代码以使用 SQlite 数据库。

\n

app.py 运行完美。我可以想象两个带有选项的下拉框。当我选择汽车品牌时,应用程序会用可用型号更新第二个下拉框。

\n

在此输入图像描述

\n

在此输入图像描述

\n

在此输入图像描述

\n

在此输入图像描述

\n

当按下提交按钮时,我想显示两个选择的值 \xe2\x80\x8b\xe2\x80\x8b 。具体来说,哪个是所选的汽车品牌,哪个是所选的型号。

\n

我在代码中包含了一条指令来显示汽车品牌的值,并显示与汽车型号对应的值 \xe2\x80\x8b\xe2\x80\x8b 。但是,我找不到获取所选车型的值的方法。

\n

在此输入图像描述

\n

我怎样才能实现这个目标?

\n

谢谢。

\n

注意:问题文本已被编辑得更加具体。问题的本质没有改变。

\n

我附上源代码和使用的模板。

\n

应用程序.py:

\n
# flask sqlalchemy\n\nfrom flask_sqlalchemy  import SQLAlchemy\n\n# app.py\n\nfrom flask import Flask, render_template, request, jsonify\n\napp = Flask(__name__)\n    \napp.config[\'SECRET_KEY\'] = "caircocoders-ednalan"\n\n# sqlite config\napp.config[\'SQLALCHEMY_DATABASE_URI\'] = \'sqlite:///testingdb.db\'\napp.config[\'SQLALCHEMY_TRACK_MODIFICATIONS\'] = False\n\n# Bind the instance to the \'app.py\' Flask application\ndb = SQLAlchemy(app)\n    \n\nclass Carbrands(db.Model):\n    __tablename__ = \'carbrands\' \n    brand_id = db.Column(db.Integer, primary_key = True)\n    brand_name = db.Column(db.String(250))\n\n    def __repr__(self):\n    \n        return \'\\n brand_id: {0} brand_name: {1}\'.format(self.brand_id, self.brand_name)\n\n\n    def __str__(self):\n\n        return \'\\n brand_id: {0} brand_name: {1}\'.format(self.brand_id, self.brand_name)\n\nclass Carmodels(db.Model):\n    __tablename__ = \'carmodels\' \n    model_id = db.Column(db.Integer, primary_key = True)\n    brand_id = db.Column(db.Integer)\n    car_models = db.Column(db.String(250))\n\n    def __repr__(self):\n    \n        return \'\\n model_id: {0} brand_id: {1} car_models: {2}\'.format(self.model_id, self.brand_id, self.car_models)\n\n\n    def __str__(self):\n\n        return \'\\n model_id: {0} brand_id: {1} car_models: {2}\'.format(self.model_id, self.brand_id, self.car_models)\n\n\n\n\n# index.html\n@app.route(\'/\', methods=["POST","GET"])\ndef index():\n\n    q = Carbrands.query.all()\n    print(q)\n\n    carbrands = q\n\n    return render_template(\'index.html\', carbrands=carbrands)\n\n\n# response.html \n@app.route("/get_child_categories", methods=["POST","GET"])\ndef get_child_categories():\n  \n    if request.method == \'POST\':\n        parent_id = request.form[\'parent_id\']\n\n        car = Carbrands.query.filter_by(brand_id=parent_id).first()\n        print("Car brand \'{0}\' parent_id \'{1}\'".format(car.brand_name, parent_id))\n        carmodels = Carmodels.query.filter_by(brand_id=parent_id).all()\n        print(carmodels)\n\n    return jsonify({\'htmlresponse\': render_template(\'response.html\', carmodels=carmodels)})\n\n\nif __name__ == "__main__":\n    app.run(debug=True)\n
Run Code Online (Sandbox Code Playgroud)\n

索引.html:

\n
<!DOCTYPE html>\n<html>\n<head>\n<meta charset="utf-8">\n<meta name="viewport" content="width=device-width, initial-scale=1.0">\n<title>Python Flask Dynamic Loading of ComboBox using jQuery Ajax and SQlite</title>\n<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />\n<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>\n<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>\n<script type="text/javascript">\n$(document).ready(function() {\n $(\'#search_category_id\').change(function(){\n        $.post("/get_child_categories", {\n         parent_id: $(\'#search_category_id\').val()\n        }, function(response){ \n                $(\'#show_sub_categories\').html(response);\n                $(\'#show_sub_categories\').append(response.htmlresponse);\n                \n        });\n        return false;\n    });\n}); \n</script>\n</head>\n<body>\n     <div class="container">\n        <div class="row">\n            <div class="col-lg-2"></div>\n        <div class="col-lg-8">\n        <h3 align="center">Python Flask Dynamic Loading of ComboBox using jQuery Ajax and SQlite</h3>\n        <form action="#" name="form" id="form" method="post">\n            <div class="form-group">\n                <label>Select Category</label>\n                <select name="search_category"  id="search_category_id" class="form-control">\n                    <option value="" selected="selected"></option>\n                    {% for row in carbrands %}\n                    <option value=\'{{row.brand_id}}\'>{{row.brand_name}}</option>\n                    {% endfor %}\n                    </select> \n            </div>\n            <div id="show_sub_categories"></div>\n            <button type="submit" class="btn btn-primary">Submit</button>\n        </form>\n        </div>\n        <div class="col-lg-2"></div>\n    </div>\n</div>\n</body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n

响应.html:

\n
<div class="form-group">\n  <label>Select Sub Category</label>\n  <select name="sub_category"  id="sub_category_id" class="form-control">\n     <option value="" selected="selected"></option>\n      {% for row in carmodels %} \n      <option value="{{row.model_id}}">{{row.car_models}}</option>\n      {% endfor %}\n  </select> \n</div>\n
Run Code Online (Sandbox Code Playgroud)\n

Ram*_*iro 5

我已经找到了解决方案。我附上源代码作为参考,以防有人对解决方案感兴趣。这个问题意味着研究工作。

在此输入图像描述

截图中可以看到,显示了选择汽车品牌和选择车型的选项。

在此输入图像描述

选择汽车品牌时,第二个下拉框会显示该汽车品牌对应的车型列表。

在此输入图像描述

当按下流程选择按钮时,应用程序会显示一条消息,指示已选择的汽车品牌和汽车型号。

在此输入图像描述

解决方案是读取包含汽车品牌和型号的数据库表。该信息被转换为 Python 字典以提供两个下拉框。选择汽车品牌时,应用程序会在第二个下拉框中显示与该汽车品牌对应的汽车型号,请参见:@app.route('/_update_dropdown')

https://api.jquery.com/jquery.getjson/文档对于解决方案至关重要。特别是 $.getJSON('/_update_dropdown',... 的实现和 $.getJSON('/_process_data',... 的实现) 在 Flask 中很多关于下拉框动态更新的例子中演示了下拉框是如何实现的,但是没有提到如何获取选定的数据;这对于继续该过程很重要。在本例中,该解决方案包含了在 Flask 中实现动态下拉框的所有细节以及所选值的处理。

在研究了可能的解决方案后,我找到了类似问题的链接。因此,我研究了该解决方案并根据我的需求进行了调整。我承认链接的作者:How to create chained selectfield inflask withoutfreshing the page? 感谢您做出的宝贵贡献。如果没有这一指导,就不可能成功解决这个问题。

应用程序.py:

# SEE: /sf/ask/1818521561/#49969686

# flask sqlalchemy

from flask_sqlalchemy  import SQLAlchemy
import sqlalchemy

# app.py

from flask import Flask, render_template, request, jsonify
import json

# Initialize the Flask application
app = Flask(__name__)
    
app.config['SECRET_KEY'] = "caircocoders-ednalan"

# sqlite config
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///cars.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Bind the instance to the 'app.py' Flask application
db = SQLAlchemy(app)
    

class Carbrands(db.Model):
    __tablename__ = 'carbrands' 
    brand_id = db.Column(db.Integer, primary_key = True)
    brand_name = db.Column(db.String(250))

    def __repr__(self):
    
        return '\n brand_id: {0} brand_name: {1}'.format(self.brand_id, self.brand_name)


    def __str__(self):

        return '\n brand_id: {0} brand_name: {1}'.format(self.brand_id, self.brand_name)

class Carmodels(db.Model):
    __tablename__ = 'carmodels' 
    model_id = db.Column(db.Integer, primary_key = True)
    brand_id = db.Column(db.Integer)
    car_model = db.Column(db.String(250))

    def __repr__(self):
    
        return '\n model_id: {0} brand_id: {1} car_model: {2}'.format(self.model_id, self.brand_id, self.car_model)


    def __str__(self):

        return '\n model_id: {0} brand_id: {1} car_model: {2}'.format(self.model_id, self.brand_id, self.car_model)


def get_dropdown_values():

    """
    dummy function, replace with e.g. database call. If data not change, this function is not needed but dictionary
could be defined globally
    """

    # Create a dictionary (myDict) where the key is 
    # the name of the brand, and the list includes the names of the car models
    # 
    # Read from the database the list of cars and the list of models. 
    # With this information, build a dictionary that includes the list of models by brand. 
    # This dictionary is used to feed the drop down boxes of car brands and car models that belong to a car brand.
    # 
    # Example:
    #
    # {'Toyota': ['Tercel', 'Prius'], 
    #  'Honda': ['Accord', 'Brio']}

    carbrands = Carbrands.query.all()
    # Create an empty dictionary
    myDict = {}
    for p in carbrands:
    
        key = p.brand_name
        brand_id = p.brand_id

        # Select all car models that belong to a car brand
        q = Carmodels.query.filter_by(brand_id=brand_id).all()
    
        # build the structure (lst_c) that includes the names of the car models that belong to the car brand
        lst_c = []
        for c in q:
            lst_c.append( c.car_model )
        myDict[key] = lst_c
    
    
    class_entry_relations = myDict
                        
    return class_entry_relations


@app.route('/_update_dropdown')
def update_dropdown():

    # the value of the first dropdown (selected by the user)
    selected_class = request.args.get('selected_class', type=str)

    # get values for the second dropdown
    updated_values = get_dropdown_values()[selected_class]

    # create the value sin the dropdown as a html string
    html_string_selected = ''
    for entry in updated_values:
        html_string_selected += '<option value="{}">{}</option>'.format(entry, entry)

    return jsonify(html_string_selected=html_string_selected)


@app.route('/_process_data')
def process_data():
    selected_class = request.args.get('selected_class', type=str)
    selected_entry = request.args.get('selected_entry', type=str)

    # process the two selected values here and return the response; here we just create a dummy string

    return jsonify(random_text="You selected the car brand: {} and the model: {}.".format(selected_class, selected_entry))




@app.route('/')
def index():

    """
    initialize drop down menus
    """

    class_entry_relations = get_dropdown_values()

    default_classes = sorted(class_entry_relations.keys())
    default_values = class_entry_relations[default_classes[0]]

    return render_template('index.html',
                       all_classes=default_classes,
                       all_entries=default_values)


if __name__ == '__main__':

    app.run(debug=True)
Run Code Online (Sandbox Code Playgroud)

索引.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>
    <div class="container">
      <div class="header">
        <h1 class="text-center text-muted">Dynamic dropdowns</h1>
      </div>

      <br><br><br>

      <div class="row">
        <div class="form-group col-xs-6">
          <label for="all_classes">Select a car</label>
          <select class="form-control" style="color: white; background: #34568B;" id="all_classes">
            {% for o in all_classes %}
                    <option value="{{ o }}">{{ o }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="form-group col-xs-6">
          <label for="all_entries">Select a model</label>
          <select class="form-control" style="color:white; background:#009B77;" id="all_entries">
            {% for o in all_entries %}
                    <option value="{{ o }}">{{ o }}</option>
            {% endfor %}
          </select>
        </div>
      </div>

      <div>
        <button type="button" style="color:white; background:#3498DB;" id="process_input">Process selection!</button>
      </div><br><br>
      <div id="processed_results">
        Here we display some output based on the selection
      </div>
    </div>
    <script src="https://code.jquery.com/jquery-1.12.4.js" type="text/javascript"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script type="text/javascript">
      $(document).ready(function() {

        $('#all_classes').change(function(){

          $.getJSON('/_update_dropdown', {
            selected_class: $('#all_classes').val()

          }).done(function(data) {
                $('#all_entries').html(data.html_string_selected);
           })
        });
        $('#process_input').bind('click', function() {

            $.getJSON('/_process_data', {
                selected_class: $('#all_classes').val(),
                selected_entry: $('#all_entries').val(),


            }).success(function(data) {
                $('#processed_results').text(data.random_text);
            })
          return false;

        });
      });
    </script>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

创建表和数据.sql:

--
-- Table structure for table `carbrands`
--


CREATE TABLE CARBRANDS ( 
    BRAND_ID INT PRIMARY KEY NOT NULL,
    BRAND_NAME CHAR(250)
);


--
-- Dumping data for table `carbrands`
--

INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (1, 'Toyota');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (2, 'Honda');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (3, 'Suzuki');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (4, 'Mitsubishi');
INSERT INTO CARBRANDS (BRAND_ID, BRAND_NAME) VALUES (5, 'Hyundai');
--
-- Table structure for table `carmodels`
--


CREATE TABLE CARMODELS (
    MODEL_ID INT PRIMARY KEY NOT NULL,
    BRAND_ID INT NOT NULL,
    CAR_MODEL CHAR(250) NOT NULL
);


--
-- Dumping data for table `carmodels`
--

INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (1, 1, 'Toyota Corolla');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (2, 1, 'Toyota Camry');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (3, 1, 'Toyota Yaris');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (4, 1, 'Toyota Sienna');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (5, 1, 'Toyota RAV4');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (6, 1, 'Toyota Highlander');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (7, 2, 'Honda HR-V');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (8, 2, 'Honda Odyssey');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (9, 3, 'Swift');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (10, 3, 'Celerio');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (11, 3, 'Ertiga');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (12, 3, 'Vitara');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (13, 4, 'Mirage');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (14, 4, 'Mirage G4');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (15, 4, 'Xpander Cross');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (16, 4, 'Montero Sport');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (17, 4, 'Strada Athlete');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (18, 5, 'Reina ');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (19, 5, 'Accent');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (20, 5, 'Elantra');
INSERT INTO CARMODELS (MODEL_ID, BRAND_ID, CAR_MODEL) VALUES (21, 5, 'Tucson');
Run Code Online (Sandbox Code Playgroud)