使用从前一个字段中选择的值填充 WTForms 选择字段

Posted

技术标签:

【中文标题】使用从前一个字段中选择的值填充 WTForms 选择字段【英文标题】:populate WTForms select field using value selected from previous field 【发布时间】:2017-05-05 01:35:43 【问题描述】:

对此的新手,尝试按照众所周知的 Flask 教程构建应用程序,使用 Flask-bootstrap、Flask-wtforms、Jinja 等

我有一个包含 2 个选择字段和一个按钮的表单。

class Form(FlaskForm): 
    school_year = SelectField('School year', choices=some_tuples_list)
    category = SelectField('Category', choices=[]) 
    submit = SubmitField('submit')

我希望只预填充第一个字段,并根据前一个字段的选定值填充另一个字段(在客户端?)。

在模板中我尝试类似

 form.school_year(**"onchange":"getCategories()") 

这工作正常(假设我返回元组列表以填充下一个字段,使用正确的 javascript 和路由)但我想要类似以下的内容

 wtf.form_field(form.school_year(**"onchange":"getCategories()")) 

这不起作用(错误:wtforms.widgets.core.htmlString object' has no attribute 'flags')

所以,我想我的问题确实是:如何在这个 wtf 表单字段上实现 onChange 事件? (这是我必须做的,还是视图函数有办法?)

提前致谢。

【问题讨论】:

我用 Javascript 管理这个。有兴趣看看是否有人有不同的解决方案。请记住,如果您计划在视图函数中使用 form.validate_on_submit(),则必须将选择选项列表加载所有可能的值,否则 WTForms 验证将失败。 @PJ Santoro 是的,但是如何在模板中的 wtf 字段中调用 Javascript? 我将在下面分享一个示例,说明我是如何实现这一点的。 【参考方案1】:

这是此逻辑的示例实现,可与 WTForms 原生功能一起使用。这里的技巧是,如果你想使用 WTForms 验证,你需要用每个可能的值来实例化表单,然后修改 Javascript 中的可用选项以显示基于其他选择的过滤值。

对于这个示例,我将使用州和县的概念(我使用大量地理数据,因此这是我构建的常见实现)。

这是我的表单,我为重要元素分配了唯一 ID,以便从 Javascript 访问它们:

class PickCounty(Form):
    form_name = HiddenField('Form Name')
    state = SelectField('State:', validators=[DataRequired()], id='select_state')
    county = SelectField('County:', validators=[DataRequired()], id='select_county')
    submit = SubmitField('Select County!')

现在,要实例化和处理表单的 Flask 视图:

@app.route('/pick_county/', methods=['GET', 'POST'])
def pick_county():
    form = PickCounty(form_name='PickCounty')
    form.state.choices = [(row.ID, row.Name) for row in State.query.all()]
    form.county.choices = [(row.ID, row.Name) for row in County.query.all()]
    if request.method == 'GET':
        return render_template('pick_county.html', form=form)
    if form.validate_on_submit() and request.form['form_name'] == 'PickCounty':
        # code to process form
        flash('state: %s, county: %s' % (form.state.data, form.county.data))
    return redirect(url_for('pick_county'))

响应县的 XHR 请求的 Flask 视图:

@app.route('/_get_counties/')
def _get_counties():
    state = request.args.get('state', '01', type=str)
    counties = [(row.ID, row.Name) for row in County.query.filter_by(state=state).all()]
    return jsonify(counties)

最后,放置在 Jinja 模板底部的 Javascript。我假设因为您提到了 Bootstrap,所以您使用的是 jQuery。我还假设这是在 javascript 中,所以我使用 Jinja 返回端点的正确 URL。

<script charset="utf-8" type="text/javascript">

$(function() 

    // jQuery selection for the 2 select boxes
    var dropdown = 
        state: $('#select_state'),
        county: $('#select_county')
    ;

    // call to update on load
    updateCounties();

    // function to call XHR and update county dropdown
    function updateCounties() 
        var send = 
            state: dropdown.state.val()
        ;
        dropdown.county.attr('disabled', 'disabled');
        dropdown.county.empty();
        $.getJSON(" url_for('_get_counties') ", send, function(data) 
            data.forEach(function(item) 
                dropdown.county.append(
                    $('<option>', 
                        value: item[0],
                        text: item[1]
                    )
                );
            );
            dropdown.county.removeAttr('disabled');
        );
    

    // event listener to state dropdown change
    dropdown.state.on('change', function() 
        updateCounties();
    );

);

</script>

【讨论】:

似乎可以完成这项工作-并且还为我提供了非常实用的 jQuery 介绍。非常感谢。 +1 用于实例化所有可能值的选择。我只是花了很长时间试图弄清楚为什么在使用 Javascript 更新选项后表单无法验证。谢谢! 我正在使用这个例子,我收到错误 NameError: name 'State' is not defined @bms9nmh StateCounty 是在别处定义的 SQLAlchemy 模型的表示,但您可以将它们替换为您正在使用的任何分层数据源。 使用生成器表达式,我正在从 sqlalchemy 生成一个元组列表。[('01', 'Alabama'), ('02', 'Alaska')...] 在渲染视图中将填充这些字段的 wtforms 选择选项。在 XHR 端点中,它将 jsonify 成 javascript 中的嵌套列表,例如:[['01', 'Alabama'], ['02', 'Alaska']...]【参考方案2】:

PJ Santoro 的回答很棒。调用了加载更新,但事件侦听器起初对我不起作用。原来我没有将“状态”换成我自己的字段 ID,因为我认为它是一个引用字段状态的关键字!哦!所以在寻找其他选项时,我发现这也有效,这可能对那里的人有用:

    // event listener to state dropdown change
$('#state').change(function() 
    updateCounties();
);

【讨论】:

是的,这是绑定更改事件的JQuery方法(上面是'纯'JS方法)。

以上是关于使用从前一个字段中选择的值填充 WTForms 选择字段的主要内容,如果未能解决你的问题,请参考以下文章

如何相互验证 wtforms 字段?

Flask WTForms 动态表单依赖项 selectField 未填充在编辑页面中

用数据填充 WTForms FormField FieldList 会在字段中生成 HTML

不是动态选择字段 WTFORMS 的有效选择

Wtforms:如何使用具有动态选择值的选择字段生成空白值

在python wtforms中选择具有动态选择值的字段。