【问题标题】:Flask WTForms dynamic select field from list instead of dbFlask WTForms 从列表而不是 db 中动态选择字段
【发布时间】:2020-05-02 21:31:26
【问题描述】:

我正在尝试使用 WTForms 创建一个动态下拉列表 (SelectField)。我已经阅读了文档并查看了很多关于堆栈的答案,所有示例都涉及迭代数据库查询。

我只是想遍历一个列表(由外部 API 调用生成)以注入 SelectField 选项。例如:

class ToolForm(FlaskForm):


    myField3 = SelectField(u'Select Account', choices=[], coerce=int)


@app.route("/test", methods=['GET', 'POST'])
def test():
    form = ToolForm()
    accounts5 = []

    if request.method == 'POST':
        if request.form['submit_button'] == 'Select Account':

            #code that generates list called "accounts5"

            acctchoices = [(c.id,c.name) for c in accounts5]
            form.myField3.choices = acctchoices

    return render_template('test.html', title='test', form=form, accounts5=accounts5)

我的相关 HTML 看起来像:

<div class="form-group">
    {{ form.myField3.label(class="form-control-label") }} {% if form.myField3.errors %} {{ 
    form.myField3(class="form-control form-control-lg is-invalid") }}
    <div class="invalid-feedback">
        {% for errors in form.myField3.errors %}
        <span>{{ error }}</span>
        {% endfor %}
    </div>
    {% else %} {{ form.myField3(class="form-control form-control-lg") }} {% endif %}
</div>
<form action="http://127.0.0.1:5000/test" method="post">


    <input type="submit" class="btn btn-outline-info" name="submit_button" value="Select Account">

</form>

当我单击“选择帐户”时,我收到 'int' object has no attribute 'id' 错误。我认为这可能是数据类型问题,所以我尝试使用字符串列表但无济于事。

我的问题是,如何从列表中填充我的 SelectField?

【问题讨论】:

  • accounts5 是什么样的?你确定它带有你可以访问的“id”和“name”吗?
  • @Till Accounts5 看起来像一个普通的列表,我现在意识到这是一个疏忽。我尝试使用像accounts5 = [("test", '1'), ("tested", '3'), ("testing", '3')] 这样的元组构建一个列表,但得到了'tuple' object has no attribute 'id'
  • 好的,在这个列表中,您已经切换了 SelectField 的 ID 和名称。为什么不先尝试简化逻辑并让 SelectField 工作?如果你设置accounts5 = [('1', 'test'), ('3','tested'),('4','testing')]form.myField3.choices = accounts5 那么它会起作用。您显示的列表没有主键的 'id' 或 'name' 属性(但您从中获取示例的数据库对象确实如此)。

标签: python flask dropdown flask-wtforms


【解决方案1】:

当您GET 使用该路由时,它会加载一个通用表单并将其呈现到页面上,而不会设置或提供任何myField3 选项。

您可以通过使用__init__ 覆盖来控制要根据特定条件加载的表单:

class ToolForm(FlaskForm):
    myField3 = SelectField(u'Select Account', choices=[], coerce=int)
    def __init__(self, accounts=None):
        super().__init__()  # calls the base initialisation and then...
        if accounts: 
            self.myField3.choices = [(c.id, c.name) for c in accounts]

然后你将根据路由请求从其他一些信息构造表单:

   @app.route("/test", methods=['GET', 'POST'])
   def test():
       # define accounts
       form = ToolForm(accounts=accounts)     

【讨论】:

  • 这是一个有趣的答案,给了我一些新的想法,但我仍然得到同样的错误'int' object has no attribute 'id,当我把它改成一个元组时,我得到了'tuple' object has no attribute 'id
  • 正如@Till 所说,只需使用self.myField.choices = accounts。只有classes 可以使用. 识别属性。像c.id 一样,否则你按索引索引一个元组,即c[0]c[1]。此错误与您未根据要填充选项的方式正确定义 accounts 的单独问题有关。
猜你喜欢
  • 2015-03-05
  • 2012-12-07
  • 2018-04-05
  • 2012-10-12
  • 1970-01-01
  • 2020-07-15
  • 2020-02-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多