使用flask和WTForms在一页中创建多个表单

使用flask和WTForms在一页中创建多个表单,forms,flask,flask-wtforms,Forms,Flask,Flask Wtforms,我在同一页上有多个表单向同一处理程序发送post请求 在烧瓶里 我正在使用wtforms生成表单 确定提交哪个表格的最佳方式是什么 我目前正在使用action=?form=oneform。我认为应该有更好的方法 实现同样的目标 我一直在使用两个烧瓶片段的组合。然后在提交时用validate_检查前缀 引用丹·雅各布的话: 例如: form1 = FormA(prefix="form1") form2 = FormB(prefix="form2") form3 = FormC(prefix="fo

我在同一页上有多个表单向同一处理程序发送post请求 在烧瓶里

我正在使用wtforms生成表单

确定提交哪个表格的最佳方式是什么

我目前正在使用action=?form=oneform。我认为应该有更好的方法
实现同样的目标

我一直在使用两个烧瓶片段的组合。然后在提交时用validate_检查前缀

引用丹·雅各布的话:

例如:

form1 = FormA(prefix="form1")
form2 = FormB(prefix="form2")
form3 = FormC(prefix="form3")
然后,添加一个隐藏字段或选中一个提交字段:

if form1.validate_on_submit() and form1.submit.data:
引用Louis Roché的话:

我的模板中有:

<input type="submit" name="btn" value="Save">
<input type="submit" name="btn" value="Cancel">

一种简单的方法是对不同的提交字段使用不同的名称。为了 例如:

forms.py:

class Login(Form):

    ...
    login = SubmitField('Login')


class Register(Form):

    ...
    register = SubmitField('Register')
views.py:

@main.route('/')
def index():

    login_form = Login()
    register_form = Register()


    if login_form.validate_on_submit() and login_form.login.data:
        print "Login form is submitted"

    elif register_form.validate_on_submit() and register_form.register.data:
        print "Register form is submitted"

    ...
上面的解决方案有一个验证错误,当一个表单导致验证错误时,两个表单都会显示一条错误消息。我改变if的顺序来解决这个问题

首先,用不同的名称定义多个SubmitField,如下所示:

class Form1(Form):
    name = StringField('name')
    submit1 = SubmitField('submit')

class Form2(Form):
    name = StringField('name')
    submit2 = SubmitField('submit')

....
temp = {'submit': True}
temp = {'submit': False, 'submit': True}
然后在view.py中添加一个过滤器:

....
form1 = Form1()
form2 = Form2()
....

if form1.identifier.data == 'FORM1' and form1.validate_on_submit():
....
if form2.identifier.data == 'FORM2' and form2.validate_on_submit():
....
现在问题解决了

如果你想深入阅读,那么继续阅读

以下是在提交时验证\u:

以下是您提交的:

当您在提交时调用form.validate\u时,无论单击哪个提交按钮,它都会检查表单是否通过HTTP方法提交。所以上面的小技巧就是添加一个过滤器来检查submit是否有数据,即form1.submit1.data

此外,我们更改了if的顺序,因此当我们单击一个submit时,它只调用该表单的validate,从而防止了两个表单的验证错误

故事还没有结束。数据如下:

它返回一个带有字段namekey和字段datavalue的dict,然而,我们的两个表单提交按钮具有相同的名称submitkey

当我们单击form1中的第一个submit按钮时,来自form1.submit1.data的调用将返回如下dict:

class Form1(Form):
    name = StringField('name')
    submit1 = SubmitField('submit')

class Form2(Form):
    name = StringField('name')
    submit2 = SubmitField('submit')

....
temp = {'submit': True}
temp = {'submit': False, 'submit': True}
毫无疑问,当我们调用if form1.submit.data:,它将返回True

当我们单击form2中的第二个submit按钮时,调用if form1.submit.data中的.data:首先在dict中添加一个键值,然后调用if form2.submit.data:添加另一个键值,最后,dict将如下所示:

class Form1(Form):
    name = StringField('name')
    submit1 = SubmitField('submit')

class Form2(Form):
    name = StringField('name')
    submit2 = SubmitField('submit')

....
temp = {'submit': True}
temp = {'submit': False, 'submit': True}
现在我们调用if form1.submit.data:,它返回True,即使我们单击的提交按钮位于form2中

这就是为什么我们需要用不同的名称定义这两个SubmitField。顺便说一下,谢谢你读到这里

使现代化 还有另一种方法可以在一个页面上处理多个表单。可以使用多个视图来处理表单。例如:

...
@app.route('/')
def index():
    register_form = RegisterForm()
    login_form = LoginForm()
    return render_template('index.html', register_form=register_form, login_form=login_form)

@app.route('/register', methods=['POST'])
def register():
    register_form = RegisterForm()
    login_form = LoginForm()

    if register_form.validate_on_submit():
        ...  # handle the register form
    # render the same template to pass the error message
    # or pass `form.errors` with `flash()` or `session` then redirect to /
    return render_template('index.html', register_form=register_form, login_form=login_form)


@app.route('/login', methods=['POST'])
def login():
    register_form = RegisterForm()
    login_form = LoginForm()

    if login_form.validate_on_submit():
        ...  # handle the login form
    # render the same template to pass the error message
    # or pass `form.errors` with `flash()` or `session` then redirect to /
    return render_template('index.html', register_form=register_form, login_form=login_form)
在template index.html中,您需要呈现这两个表单,并将“操作”属性设置为“目标视图”:

<h1>Register</h1>
<form action="{{ url_for('register') }}" method="post">
    {{ register_form.username }}
    {{ register_form.password }}
    {{ register_form.email }}
</form>

<h1>Login</h1>
<form action="{{ url_for('login') }}" method="post">
    {{ login_form.username }}
    {{ login_form.password }}
</form>

作为其他答案,我还为页面上的每个表单的每个提交按钮指定了一个唯一的名称

然后,flask web操作如下所示-注意formdata和obj参数,它们有助于相应地初始化/保留表单字段:

@bp.route('/do-stuff', methods=['GET', 'POST'])
def do_stuff():
    result = None

    form_1 = None
    form_2 = None
    form_3 = None

    if "submit_1" in request.form:
        form_1 = Form1()
        result = do_1(form_1)
    elif "submit_2" in request.form:
        form_2 = Form2()
        result = do_2(form_2)
    elif "submit_3" in request.form:
        form_3 = Form3()
        result = do_3(form_3)

    if result is not None:
        return result

    # Pre-populate not submitted forms with default data.
    # For the submitted form, leave the fields as they were.

    if form_1 is None:
        form_1 = Form1(formdata=None, obj=...)
    if form_2 is None:
        form_2 = Form2(formdata=None, obj=...)
    if form_3 is None:
        form_3 = Form3(formdata=None, obj=...)

    return render_template("page.html", f1=form_1, f2=form_2, f3=form_3)


def do_1(form):
    if form.validate_on_submit():
        flash("Success 1")
        return redirect(url_for(".do-stuff"))


def do_2(form):
    if form.validate_on_submit():
        flash("Success 2")
        return redirect(url_for(".do-stuff"))

def do_3(form):
    if form.validate_on_submit():
        flash("Success 3")
        return redirect(url_for(".do-stuff"))

示例:单个html页面中的多个WTForm

app.py

模板/index.html

showData.html


我没有使用WTForms,但无论如何都应该工作。这是一个非常快速和简单的答案;您所需要做的就是为submit按钮使用不同的值。然后,您可以根据每种情况执行不同的def

在index.html中:


这里有一个简单的技巧

假设你有

表格1、表格2和索引


我通常使用一个隐藏标记作为标识符

以下是一个例子:

class Form1(Form):
    identifier = StringField()
    name = StringField('name')
    submit = SubmitField('submit')

class Form2(Form):
    identifier = StringField()
    name = StringField('name')
    submit = SubmitField('submit')
然后可以在view.py中添加过滤器:

....
form1 = Form1()
form2 = Form2()
....

if form1.identifier.data == 'FORM1' and form1.validate_on_submit():
....
if form2.identifier.data == 'FORM2' and form2.validate_on_submit():
....
最后在HTML中:

<form method="POST">
  {{ form1.indentifier(hidden=True, value='FORM1') }}
</form>
<form method="POST">
  {{ form2.indentifier(hidden=True, value='FORM2') }}
</form>

如果在If语句中这样做,它将检查标识符是什么,如果标识符相等,它将运行代码中的表单内容。

IMHO更新是最佳答案。但是@app.routeI使用的第一个方法中似乎缺少methods=['POST'],但是form1.submit1.data和forn2.submit2.data的行始终返回false。如何处理?@Sivaramakrishnan也许你可以创建一个新问题,包括相关代码,然后在这里发布一个链接。第二个更新是最好的答案。如果有人想知道,你实际上可以在路径“/”下拥有所有功能——只要你记得在表单动作中添加花括号部分。登录和注册不需要单独的路由,即使这是注册/登录页面的一个很好的特性。但是,有时你想在同一个页面上放置大量不同的表单,而不想处理大量的路由。这也解决了我的验证错误消息不出现的问题。非常感谢。对我来说,最简单的解决方案是执行if form.submit.data和form.validate,并确保SubmitFields具有不同的名称。如果login.validate\u on\u submit和login\u form.login.data,则进行小的更正:应该是if login\u form.validate\u on\u submit和login\u form.login.data:@Hieu谢谢。那么SubmitField'texthore'指定'texthore'是标记的name属性的值?像这样:科雷普斯
onds提交“登录”字段。请注意此处所述的顺序,所提供的链接已过时。这是解决此问题的最佳答案!这种方法在所有提出的方法中效果最好。所有其他方法在技术上也都有效,但会导致表单中出现非预期的验证错误。基本上,它会导致表单未点击的预期行为被忽略/失效/不干扰。谢谢
Form1  <form method="post" action="{{ url_for('index',formid=1) }}">

Form2  <form  method="post" action="{{ url_for('index',formid=2) }}">
@bp.route('/index', methods=['GET', 'POST'])
def index():
    formid = request.args.get('formid', 1, type=int)
    if formremote.validate_on_submit() and formid== 1:
        return "Form One"
    if form.validate_on_submit() and formid== 2:
        return "Form Two"
class Form1(Form):
    identifier = StringField()
    name = StringField('name')
    submit = SubmitField('submit')

class Form2(Form):
    identifier = StringField()
    name = StringField('name')
    submit = SubmitField('submit')
....
form1 = Form1()
form2 = Form2()
....

if form1.identifier.data == 'FORM1' and form1.validate_on_submit():
....
if form2.identifier.data == 'FORM2' and form2.validate_on_submit():
....
<form method="POST">
  {{ form1.indentifier(hidden=True, value='FORM1') }}
</form>
<form method="POST">
  {{ form2.indentifier(hidden=True, value='FORM2') }}
</form>