Flask app submit target=“_blank” form only after wtforms validation

懵懂的女人 提交于 2020-01-01 17:04:52

问题


In my Flask app I have a form generated with wtforms and jinja templates. If validation passes I want to redirect in a new tab, else I want to stay on the same page and display the errors. However if I set target="_blank" in my form, it opens a new tab without validation passing and shows the errors there. Removing target="_blank" will not open a new tab. Is there a way of achieving this without rewriting the whole validation in js? Thanks!

Code:

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(not that relevant but for the sake of completness):

{% 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 %}

回答1:


Main issue

You must pass the form object as well as the variables representing your form fields namely field1 and field2.

Details

What is being stated above means that you need to change:

return redirect('/my_redirect_uri')

to

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

This also means that you have to adjustments to your view method:

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

Now there are some improvements to your program:

  • Code less principle:

Replace if request.method == 'POST' and form.validate(): by if form.validate_on_submit(): (you save one instruction)

  • Use url_for():

For the sake of scalability because in future versions and reedits of your program, any changes made to route names will be automatically available when using url_for() as it generates URLs using the URL map. You may use it in return redirect('/my_redirect_uri') (you may check the link I provided for further information)

  • Use sessions:

Sessions will make your application "able to remember" the form data being sent. In your example, you can use a session this way:

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

This means, for example, the above line:

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

must be changed to:

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

Note that if you want to implement sessions, you will need to set a secret key because they are stored on the client side, so they need to be protected (cryptographically in Flask's philosophy). This mean you must configure your application this way:

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

Actually, the problem is not related to the browser tab you opened. The whole issue emanates from the redirect() statement.

More details on why it is good to use sessions? Check the next last section:

A word about redirect:

Your POST request is handled by redirect, consequently you loose access to the form data when the POST request ends.

The redirect statement is simply a response which, when received, the browser issues a GET request. This mechanism is there mainly for the following (and similar) situation:

If you try to refresh the same browser window on which you submitted the form data, the browser will prompt you a pop up window to confirm that you want to send the data (again) because the browser remembers, by design, the last request it performed. Of course, this is nasty for the user of your application. There we need sessions. This is also helpful for the browser tab to which you redirect.



来源:https://stackoverflow.com/questions/40817966/flask-app-submit-target-blank-form-only-after-wtforms-validation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!