如何使用ajax调用(即Select2)填充WTForms SelectField?

时间:2017-02-11 22:53:55

标签: ajax flask select2 wtforms flask-wtforms

我正在尝试使用Flask + WTForms + Select2(ajax调用)实现一个Web应用程序,但遗憾的是没有取得很大成功。主要问题是我的一个WTForms类中的属性“选择”,因为我无法理解如何使用ajax调用填充选择菜单并让WTForms类来管理这些数据。 这是我的解决方法:

class insertData(FlaskForm):
    ...
    feature_tag = SelectMultipleField(
        u'Features',
        choices=[(0, "")],
        coerce=int,
        render_kw={"multiple": "multiple"},
        id="feature_tag_sel2")
    ...

在模板中调用它:

<div class="col-sm-4">
    {{form.feature_tag}}
</div>

由Select2管理:

$("#feature_tag_sel2").select2({
    minimumInputLength: 2,
    ajax: {
      url: "/select/api/feature",
      dataType: 'json',
      data: function (params) {
          return { q: params.term };
      },
      processResults: function (data) {
          return {results: data};
      },
      cache: false
    }
});

最后,ajax调用引用此代码:

@app.route('/select/api/feature')
def suggestion_feature():
    param = request.args.get('q', '')
    q = db.session.query(Feature).filter(Feature.nome_f.startswith(param)).all()
    value = [dict(id=i.id, text=i.nome_f) for i in q]
    return json.dumps(value)

当这段代码运行时,无论select的值是什么,validate_on_submit都会出现错误:我可以从Select2菜单中选择多个值,但当然0的任何值都不是有效选择。然后我尝试通过实现新的字段定义来阻止此错误的传播:

class Select2MultipleField(SelectMultipleField):
    def pre_validate(self, form):
        # Prevent "not a valid choice" error
        pass

此代码有效,但无论如何它都是一种解决方法。例如,当validate_on_submit在表单中发现另一个错误并重新加载页面时,所有选定的值都将丢失。当我需要编辑数据时也会发生同样的情况。总之,这种解决方法让我失去了WTForms的许多优点。

问题是:有没有方法将WTForms SelectField与使用ajax调用检索的数据集成?

1 个答案:

答案 0 :(得分:0)

根据我对您的问题的了解,使用WTForm的ajax select2遇到了两个问题。

  • 提交表单时不是有效选择
  • 所选值丢失,并且表单重新加载或出错

让我尝试解决以下问题:

提交表单时不是有效选择

对于第一个无效选择的问题,您可以告诉wtf表单不要在提交表单时对其进行验证,是的,解决方法!它也对我有用。

class Select2MultipleField(SelectMultipleField):
    def pre_validate(self, form):
        # Prevent "not a valid choice" error
        pass

所选值丢失,并且表单重新加载或出错

引用您的问题

validate_on_submit在表单和页面中发现另一个错误时 重新加载后,所有选择的值都将丢失。当我发生同样的事情 需要编辑数据。

是的,这确实按预期工作。首先,选择字段不包含任何选项,因为来自选择字段的所有数据都是从远程ajax调用获取的,这意味着在使用WTForm创建时,选择字段未提供任何数据选择在此处调用作为您的代码

class insertData(FlaskForm):
    ...
    feature_tag = SelectMultipleField(
        u'Features',
        choices=[(0, "")],
        coerce=int,
        render_kw={"multiple": "multiple"},
        id="feature_tag_sel2")
    ...

实际上,您不需要提供参数choices,因为您的数据是从远程ajax调用中调用的,并且您已经解决了问题Not a valid choice

要回答您的问题并解决第二个问题,您可以检查数据值是否随选择字段一起附加,如下所示,并按以下方式将其创建为选择字段的选项:

<div class="col-sm-4">
    {{form.feature_tag}}
</div>

<script>
$(document).ready(function(){
$("#feature_tag_sel2").select2({
    minimumInputLength: 2,
    ajax: {
      url: "/select/api/feature",
      dataType: 'json',
      data: function (params) {
          return { q: params.term };
      },
      processResults: function (data) {
          return {results: data};
      },
      cache: false
    }
});

{# check if select field come with data previously selected #}
{% if form.feature_tag.data %}
{# trigger an ajax call to url with parameter of this value #}

        $.ajax("/select/api/feature?q={{form.feature_tag.data}}", {
                dataType: "json"
        }).done(
                function(data) { 
                    text = data.items[0].text // text returned from your url
                    id = data.items[0].id. // id returned from your url
                    
                    // created an option for the select field
                    var newOption = new Option(text, id, false, false)

                    $('#{{form.feature_tag.id}}').append(newOption).trigger('change')

                    $('#{{form.feature_tag.id}}').val(id).trigger('change')
    
                }
        );

{% endif %}


});

</script>

这样,您的选择字段在查看或编辑它之前应该已经包含了先前选择的值:)

希望获得帮助!谢谢