同一页面上相同 wtform 表单的多个独立实例

Multiple, independent, instances of same wtform form on same page

我正在玩项目管理应用程序。我正在循环项目、项目中的列表以及每个列表中的任务。我希望 CreateTask() 表单出现在每个列表的任务下,它确实出现了。

原因是我有2个隐藏字段,项目id和列表id。

问题是,虽然表格显示正确,但如果我输入任务名称并提交,它所做的只是刷新页面,并且每个表格都有我在第一个表格中输入的文本。

如何在同一页面的多个实例中使用相同的 WTForms 表单并让它们独立工作?

一个表单,项目和列表 ID 设置为 select 字段,有效。我能够添加任务。

from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SelectField, TextAreaField, SubmitField, HiddenField
from wtforms.validators import DataRequired, Length, ValidationError

app = Flask(__name__)
app.config['SECRET_KEY'] = 'f0c4803ba453fc7f8d0c43df21413916'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)

##################################
######    Database Tables   ######
##################################

class Project(db.Model):
  p_id = db.Column(db.Integer, primary_key=True)
  p_title = db.Column(db.String(300), nullable=False)
  p_list = db.relationship('List', backref="project", lazy=True)
  p_task = db.relationship('Task', backref="project", lazy=True)

  def __repr__(self):
    return f"P('p_id: {self.p_id}','p_title: {self.p_title}','p_list: {self.p_list}', 'p_task: {self.p_task}')" 

class List(db.Model):
  l_id = db.Column(db.Integer, primary_key=True)
  l_title = db.Column(db.String(300), nullable=False)
  l_project = db.Column(db.Integer, db.ForeignKey('project.p_id'), nullable=False)
  l_task = db.relationship('Task', backref="list", lazy=True)

  def __repr__(self):
    return f"L('l_id: {self.l_id}','l_title: {self.l_title}','l_project: {self.l_project}')"

class Task(db.Model):
  t_id = db.Column(db.Integer, primary_key=True)
  t_title = db.Column(db.Integer, nullable=False)
  t_list = db.Column(db.Integer, db.ForeignKey('list.l_id'), nullable=False)
  t_project = db.Column(db.Integer, db.ForeignKey('project.p_id'), nullable=False)

  def __repr__(self):
    return f"T('t_id: {self.t_id}',' t_title: {self.t_title}','t_project: {self.t_project}')"


##################################
#####         Forms         ######
##################################

class CreateTask(FlaskForm):
  project = HiddenField('Project:', validators=[DataRequired()])
  list_select = HiddenField('List:', validators=[DataRequired()])
  task_title = StringField('Task Title:', validators=[DataRequired()])
  submit = SubmitField('Add Task')

##################################
######        Run App       ######
##################################

@app.route('/try', methods=['GET', 'POST'])
def index():
  form = CreateTask(request.values, project="foo", fld2="bar")
  if form.validate_on_submit():
    p_id = form.project.data   
    l_id = form.list_select.data   
    task = form.task_title.data
    new_task = Task(t_project=p_id, t_list=l_id, t_title=task)
    db.session.add(new_task)
    db.session.commit()
  project = Project.query.all()
  return render_template('index.html', form=form, project=project)

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




{% for item in project %}
  <div style="padding: 30px; maring: 30px; border: 1px solid #000;">
    <h2>{{ item.p_title }}</h2><br><hr><br>
    {% for item2 in item.p_list %}
      <h3>{{ item2.l_title }}</h3><br><hr><br>
      {% for item3 in item2.l_task %}
        <h4>{{ item3.t_title }}</h4><br><br>
      {% endfor %}
      <br><br>
      <div style="padding: 40px;">
        <form action="" method="POST">
          {{ form.hidden_tag() }}          
          {{ form.project(value=item.p_id) }}
          {{ form.list_select(value=item2.l_id) }}
          {{ form.task_title.label }}<br>
          {{ form.task_title }}<br><br>
          {{ form.submit }}
        </form>
      </div>
    {% endfor %}
  </div>
{% endfor %}

您不会创建表单的两个实例,您只需渲染同一个实例两次。

所以在app.py中应该是:

def index():
    form1 = CreateTask(request.values, project="foo", fld2="bar")
    form2 = CreateTask(request.values, project="foo", fld2="bar")
    ...
    return render_template('index.html', form1=form1, form2=form2, project=project)

并且必须相应地更改模板。如果你想在模板中迭代它们,你可以把这两个实例放在一个列表中。

但请注意,如果您在一个页面上有多个表单,则只会提交一个表单。如果你想一次编辑多个项目,你需要迭代生成一个表单(至少如果你不添加一些 JS 魔法)。