如何在 flask-wtf wtforms 中组合不同的字段类型

How to combine different field types in flask-wtf wtforms

我正在使用 flask-wtf 表单构建表单。我有一个字段,用户可以在其中 select 多个选项。如果他们想要的选择不在我的列表中。我想允许用户 select“其他”并通过文本字段指定他们的选项。

我没有找到在 wtforms 中执行此操作的方法。我到处搜索,似乎无法在任何地方找到答案。我正在做的事情绝不是一个独特的场景,而且在我的想象中会很常见。所以我想我可能 thinking/going 错了。

question1_options = [('rice','rice'),('chips','chips'),('tuna','tuna'), ('other', 'other')]
question2_options = [('yes', 'yes'),('no', 'no')]

class MyForm(FlaskForm):
    q1 = SelectMultipleField('favourite food?', choices=question1_options)
    q2 = RadioField('do you like football', choices=question2_options)

我想达到的目标:

将 SelectMultipleField 与 StringField 组合在一起,以便在列表中没有合适的选项时使用。用户可以 select 其他并输入他们想要的内容

我找不到合并两个字段的方法。

我认为应该是两个分开的字段始终可见

q1_options = [('rice','rice'),('chips','chips'),('tuna','tuna')] #, ('other', 'other')]

class MyForm(FlaskForm):
    q1 = SelectMultipleField('Favourite food?', choices=q1_options)
    q1_other = StringField('Other favourite food?')

或者它应该使用 JavaScript 来显示 StringField 当你 select other.

我尝试创建最少的工作代码。

因为它使用 multiple select 所以它需要更复杂的 JavaScript 代码。

from flask import Flask, render_template_string
from flask_wtf import FlaskForm
from wtforms import SelectMultipleField, StringField, RadioField
from wtforms.validators import DataRequired, Optional

# --- form ---

q1_options = [('rice','rice'),('chips','chips'),('tuna','tuna'), ('other', 'other')]

class MyForm(FlaskForm):
    q1_list  = SelectMultipleField('Favourite food?', choices=q1_options, validators=[DataRequired()])
    q1_other = StringField('Other', validators=[Optional()])

# --- app ---

app = Flask(__name__)
app.config['SECRET_KEY'] = 'qwerty123456'

@app.route('/', methods=['GET', 'POST'])
def index():
    form = MyForm()
    #print(dir(form))
    print(form.validate_on_submit())
    #if form.validate_on_submit():
    if form.is_submitted():
        print('list:', form.q1_list.data)
        print('other:', form.q1_other.data)

    return render_template_string('''<!DOCTYPE html>    
<html>
<head>
<meta charset="utf-8">
</head>
<body>    

<form method="POST">
    {{ form.q1_list.label }}<br>
        {{ form.q1_list(onchange="get_selection(this);") }}<br>
        {{ form.q1_other(style="display:none") }}<br>
    <input type="submit" value="Go">
</form>

<script language="javascript">
//var q1_list  = document.querySelector("#q1_list");
var q1_other = document.querySelector("#q1_other");

function get_selection(select){
  //console.log(select);
  //console.log(select.value);
  //console.log(select.options);

  var opts = [];
  var opt;    
  
  var len = select.options.length;
  
  for(var i = 0; i < len; i++) {
    opt = select.options[i];

    if (opt.selected) {
      opts.push(opt.value);
    }
  }    
  
  //console.log(opts);
  
  if(opts.includes('other')){
    q1_other.style.display = 'block';
  }else{
    q1_other.style.display = 'none';
  }
}
</script>

</body>
</html>
''', form=form)

# --- start ---

if __name__ == '__main__':
    app.debug = True
    app.run()

addEventListener相同而不是onchange

<form method="POST">
    {{ form.q1_list.label }}<br>
        {{ form.q1_list() }}<br>
        {{ form.q1_other(style="display:none") }}<br>
    <input type="submit" value="Go">
</form>

<script language="javascript">
//var q1_list  = document.querySelector("#q1_list");
var q1_other = document.querySelector("#q1_other");

q1_list.addEventListener('input', function(event) {
  //console.log(event);
  //console.log(event.target.value);
  //console.log(event.target.options);

  var select = event.target;
  
  //console.log(select.options);

  var opts=[];
  var opt;    
  
  var len = select.options.length;
  
  for(var i = 0; i < len; i++) {
    opt = select.options[i];

    if (opt.selected) {
      opts.push(opt.value);
    }
  }    
  
  //console.log(opts);
  
  if(opts.includes('other')){
    q1_other.style.display = 'block';
  }else{
    q1_other.style.display = 'none';
  }
}, false);
</script>