如何在不刷新页面的情况下在烧瓶中创建链式选择域?

我目前正在使用wtf处理地址表单,其中包含Country,State,City ..等等。 数据库全部使用FK设置。

class Country(db.Model): __tablename__ = 'countries' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) users = db.relationship('User', backref='countries', lazy='dynamic') class City(db.Model): __tablename__ = 'cities' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), unique=True) countries_id = db.Column(db.Integer, db.ForeignKey('countries.id')) 

现在我正在尝试实现链式选择域排序效果以优化用户体验。 期望的效果是不离开或刷新页面以使selectfield拉取数据取决于先前的选择字段。

例如,用户在国家/地区选择澳大利亚,然后国家的第二个选择区域应仅包含澳大利亚的州。

我已经对这个主题做了一些研究,但却无法提出令人满意的解决方案。 以下是我发现的两种可能尚未解决的解决方案。

1.使用jQuery-plugin,例如Chained。 但是,此插件需要逐行编码。 如果我采用这种解决方案,那么至少会有另外400多条线路,这不是非常pythonic。 例如:

  -- 3 series 5 series 6 series A3 A4 A5  

2.使用Wtf的“选择具有动态选择值的字段”,这也是不可取的,因为它只根据前一个选择字段的默认值拉取数据一次。 例如:如果国家/地区的默认选择字段是澳大利亚,则州选择字段仅包含澳大利亚境内的州。 当你改变国家选择字段说到美国时,州选择字段仍然只包含澳大利亚境内的州。 下面是wtf文档中列出的此方法的教程:

 class UserDetails(Form): group_id = SelectField(u'Group', coerce=int) def edit_user(request, id): user = User.query.get(id) form = UserDetails(request.POST, obj=user) form.group_id.choices = [(g.id, g.name) for g in Group.query.order_by('name')] 

从上面的研究中,我认为满意的解决方案应该介于两者之间,它肯定应该涉及一些Javascript来监视客户端活动而不向服务器发送请求。 有没有人得到满意的烧瓶框架解决方案?

如果你想在客户端上运行一些动态的东西,就无法编写一些JavaScript。 幸运的是,这不是你估计的400多行。 这个例子不使用WTForms,但这并不重要。 关键部分是将可用选项作为JSON发送,并动态更改可用选项。 这是一个单个文件可运行的Flask应用程序,它演示了基本的想法。

 from flask import Flask, render_template_string app = Flask(__name__) @app.route('/') def index(): systems = { 'PlayStation': ['Spyro', 'Crash', 'Ico'], 'N64': ['Mario', 'Superman'] } return render_template_string(template, systems=systems) template = """ 
  
 """ app.run() 

我最近遇到了类似的问题,并使用这个答案的想法解决了它。

一个最小的例子可能如下所示:

在此处输入图像描述

所以,只需要两个下拉菜单,第二个下拉菜单取决于第一个选择的值; 页面上的所有其他元素不受此选择的影响(此处我只使用一个复选框)。 一旦做出选择,下拉菜单下方的按钮将触发一个动作,然后结果可以再次显示在页面上(这里,我只更新按钮下方的句子,但当然你也可以做更合理的事情),例如至: 在此处输入图像描述

HTML文件看起来像这样(位于templates/index.html ):

       

Dynamic dropdowns

Check me and I don't change status when you select something below

Select me




Here we display some output based on the selection

相应的python脚本如下所示:

 from flask import Flask, render_template, request, jsonify import json # Initialize the Flask application app = Flask(__name__) def get_dropdown_values(): """ dummy function, replace with eg database call. If data not change, this function is not needed but dictionary could be defined globally """ class_entry_relations = {'class1': ['val1', 'val2'], 'class2': ['foo', 'bar', 'xyz']} 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 += ''.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 {} and {}".format(selected_class, selected_entry)) @app.route('/') def index(): """ Initialize the dropdown menues """ 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)