FlaskForm 必须重新加载 select 个选项

FlaskForm had to reload select choices

我是 Python 和 Flask 的新手。我正在尝试使用 WTForm FlaskForm,但在 SelectField 中的选择有问题。我正在像这样构建我的表格。

class FightForm(FlaskForm):
    fight_id = StringField('fight_id', render_kw={'readonly': True})
    fight_type_id = SelectField('fight_type_id', 
        choices=[(t.fight_type_id, t.type_name) for t in fight_type.query.all()], validate_choice=False, validators=[DataRequired()])

这些选择似乎只加载了 1 次。如果我去添加一个新的 fight_type,我必须停止应用程序并重新启动它才能刷新。

另外,我找到了这个答案,,但是 FlaskForm 不会触发这个建议的 __init__ 函数。

无论如何我临时将其更改为 Form 并收到错误消息说 fight_type_id 不属于 form(释义)。

我希望每次调用该页面时都刷新这些内容。

我认为你应该看看 WTForms-SQLAlchemy 扩展。
QuerySelectField 根据提交的数据库查询动态加载所有数据库条目。可以为条目的标签定义一列。提交表单时,自动从数据库中查询选中的对象,通过字段返回。

烧瓶 (app.py)
from flask import (
    Flask,
    redirect,
    render_template,
    request,
    url_for
)
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from flask_wtf.csrf import CSRFProtect
from wtforms.validators import InputRequired
from wtforms_sqlalchemy.fields import QuerySelectField

app = Flask(__name__)
app.secret_key = b'your secret here'
db = SQLAlchemy(app)
csrf = CSRFProtect(app)

class FightType(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False, unique=True)

class Fight(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    type_id = db.Column(db.Integer, db.ForeignKey('fight_type.id'))
    type = db.relationship('FightType', backref='fights')

class FightForm(FlaskForm):
    type = QuerySelectField(
        get_label='name',
        query_factory=lambda: FightType.query.all(),
        validators=[InputRequired()]
    )

with app.app_context():
    db.drop_all()
    db.create_all()

    types = [FightType(name=f'type-{i}') for i in range(10)]
    db.session.add_all(types)
    db.session.commit()

@app.route('/')
def index():
    fights = Fight.query.all()
    return render_template('index.html', **locals())

@app.route('/fight/new', methods=['GET', 'POST'])
def fight_create():
    form = FightForm(request.form)
    if form.validate_on_submit():
        fight = Fight()
        form.populate_obj(fight)
        db.session.add(fight)
        db.session.commit()
        return redirect(url_for('index'))
    return render_template('create.html', **locals())

@app.route('/fight/<int:fight_id>/edit', methods=['GET', 'POST'])
def fight_update(fight_id):
    fight = Fight.query.get_or_404(fight_id)
    form = FightForm(request.form, obj=fight)
    if form.validate_on_submit():
        form.populate_obj(fight)
        db.session.commit()
        return redirect(url_for('index'))
    return render_template('update.html', **locals())
HTML (templated/index.html)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Index</title>
  </head>
  <body>
    <a href="{{ url_for('fight_create') }}">New</a>
    <ul>
      {% for f in fights -%}
      <li>
        <a href="{{ url_for('fight_update', fight_id=f.id) }}">
          {{ f.id }} - {{ f.type.name }}
        </a>
      </li>
      {% endfor -%}
    </ul>
  </body>
</html>
HTML (templates/create.html, templates/update.html)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Fight</title>
  </head>
  <body>
    <form method="post">
      {{ form.csrf_token }}
      {{ form.type.label }} {{ form.type() }}
      <input type="submit" value="Go">
    </form>
  </body>
</html>