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

2024-04-28 11:47:30 发布

您现在位置:Python中文网/ 问答频道 /正文

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

我正在使用wtforms生成表单。

确定提交哪一份表格的最佳方法是什么?

我正在使用action="?form=oneform"。我想应该有更好的方法 为了达到同样的目的?


Tags: 方法目的form处理程序表单烧瓶actionpost
3条回答

我用了两个瓶子碎片的组合。The first adds a prefix to a form然后检查前缀validate_on_submit()。I use also Louis Roché's template to determine what buttons are pushed in a form

引用丹•雅各伯的话:

示例:

form1 = FormA(prefix="form1")
form2 = FormB(prefix="form2")
form3 = FormC(prefix="form3")

然后,添加一个隐藏字段(或者只检查一个提交字段):

if form1.validate_on_submit() and form1.submit.data:

引用路易斯·罗奇的话:

我的模板中有:

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

要确定views.py文件中的服务器端传递了哪个按钮:

if request.form['btn'] == 'Save':
    something0
else:
    something1

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

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

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

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

....

然后在view.py中添加筛选器:

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

if form1.submit1.data and form1.validate(): # notice the order 
....
if form2.submit2.data and form2.validate(): # notice the order 
....

现在问题解决了。

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

这里是validate_on_submit()

def validate_on_submit(self):
    """
    Checks if form has been submitted and if so runs validate. This is
    a shortcut, equivalent to ``form.is_submitted() and form.validate()``
    """
    return self.is_submitted() and self.validate()

这里是is_submitted()

def is_submitted():
    """Consider the form submitted if there is an active request and
    the method is ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
    """
    return _is_submitted()  # bool(request) and request.method in SUBMIT_METHODS

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

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

故事还没结束。这里是.data

@property
def data(self):
    return dict((name, f.data) for name, f in iteritems(self._fields))

它返回一个带有字段名(key)和字段数据(value)的dict,但是,我们的两个表单提交按钮具有相同的名称submit(key)!

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

temp = {'submit': True}

毫无疑问,当我们调用if form1.submit.data:时,它返回True

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

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)

在模板(index.html)中,您需要呈现两个表单并将action属性设置为目标视图:

<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>

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

forms.py格式:

class Login(Form):

    ...
    login = SubmitField('Login')


class Register(Form):

    ...
    register = SubmitField('Register')

视图.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"

    ...

相关问题 更多 >