【问题标题】:Flask app submit target="_blank" form only after wtforms validationFlask 应用程序仅在 wtforms 验证后提交 target="_blank" 表单
【发布时间】:2016-11-26 11:40:30
【问题描述】:

在我的 Flask 应用程序中,我有一个使用 wtformsjinja 模板生成的表单。如果验证通过,我想在新选项卡中重定向,否则我想留在同一页面上并显示错误。但是,如果我在我的表单中设置target="_blank",它会打开一个新选项卡而没有通过验证,并在那里显示错误。删除 target="_blank" 不会打开新标签页。有没有办法在不重写 js 中的整个验证的情况下实现这一点?谢谢!

代码:

from wtforms import Form, TextAreaField, StringField, validators

class SubmitForm(Form):
    field1 = StringField(u'field1', [validators.DataRequired()])
    field2 = TextAreaField(u'field2', [validators.DataRequired()])

@app.route('/', methods=['POST'])
def sub():
    form = SubmitForm(request.form)
    if request.method == 'POST' and form.validate():
        # great success
        return redirect('/my_redirect_uri')
    return render_template('index.html', form=form)

@app.route('/')
def layout():
    return render_template('index.html', form=SubmitForm())

index.html:

{% from "_formhelpers.html" import render_field %}
<form method=post action="/" target="_blank">
  <dl>
    {{ render_field(form.field1) }}
    {{ render_field(form.field2) }}
  </dl>
  <p><input type=submit value=Submit>
</form>

_formhelpers.html(不那么相关,但为了完整起见):

{% macro render_field(field) %}
  <dt>{{ field.label }}
  <dd>{{ field(**kwargs)|safe }}
  {% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </dd>
{% endmacro %}

【问题讨论】:

  • 我猜你是对的。您需要编写一个简单的控制器来验证您的 Ajax 请求,然后您可以打开新选项卡,

标签: python flask wtforms


【解决方案1】:

主要问题

您必须传递form 对象以及代表表单字段的变量,即field1field2

详情

上面所说的意味着你需要改变:

return redirect('/my_redirect_uri')

return redirect('/my_redirect_uri', form=form, field1=field1, field2=field2)

这也意味着你必须调整你的视图方法:

@app.route('/', methods=['POST'])
def sub():
    form = SubmitForm(request.form)
    if request.method == 'POST' and form.validate():
        # great success
        field1 = form.field1.data
        field2 = form.field2.data
        return redirect('/my_redirect_uri', form=form, field1=field1, field2=field2)
    return render_template('index.html', form=form)

现在您的程序有一些改进:

  • 无代码原则:

if request.method == 'POST' and form.validate(): 替换为if form.validate_on_submit():(你节省了一条指令)

为了scalability,因为在您的程序的未来版本和重新编辑中,在使用url_for() 时,对路由名称所做的任何更改都将自动可用,因为它使用 URL 映射生成 URL。您可以在return redirect('/my_redirect_uri') 中使用它(您可以查看我提供的链接以获取更多信息)

  • 使用会话:

会话将使您的应用程序“能够记住”正在发送的表单数据。在您的示例中,您可以通过这种方式使用会话:

session['field1'] = form.field1.data
session['field2'] = form.field2.data

这意味着,例如,上面的行:

return redirect('/my_redirect_uri', form=form, field1=field1, field2=field2)

必须改为:

return redirect('my_redirect_uri', form=form, session.get('field1'), session.get('field2'))

请注意,如果要实现会话,则需要设置密钥,因为它们存储在客户端,因此需要保护它们(在 Flask 的哲学中是加密的)。这意味着您必须以这种方式配置您的应用程序:

app.config['SECRET_KEY'] = 'some secret phrase of your own'

其实问题与你打开的浏览器标签无关。整个问题源于redirect() 声明。

关于为什么使用会话很好的更多详细信息?检查下最后一部分:

关于重定向的一句话:

您的 POST 请求由 redirect 处理,因此当 POST 请求结束时您无法访问表单数据。

重定向语句只是一个响应,当收到该响应时,浏览器会发出一个 GET 请求。该机制主要用于以下(和类似)情况:

如果您尝试刷新提交表单数据的同一浏览器窗口,浏览器将提示您一个弹出窗口,以确认您要(再次)发送数据,因为浏览器会根据设计记住它执行的最后一个请求。当然,这对您的应用程序的用户来说是令人讨厌的。我们需要会话。这对于您重定向到的浏览器选项卡也很有帮助。

【讨论】:

  • 试过这个。在出现错误的情况下,仍然会打开一个带有错误表单的新选项卡。总比没有好,但如果想要在上一个选项卡中显示错误,则必须进行 js 验证。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 2016-05-30
  • 2012-11-04
  • 2013-08-17
  • 2017-05-26
相关资源
最近更新 更多