form.validate_on_submit(): 和 {{ form.csrf_token }} 无法在具有两种形式的 view.html 中工作
form.validate_on_submit(): and {{ form.csrf_token }} not working in a view.html with two forms
如果默认值为“0”,则每个字段中的消息:“此字段为必填项”。
“compute0”和“compute1”上方有消息“csrf_token CSRF Token”。
只有 compute0 有效。
点击 compute0 显示结果。
单击 compute1 什么也没显示。
form 和 form1 有 3 个输入。
compute0 和 compute1 调用 (math.sin(r))* t + u.
from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import TextField, BooleanField, PasswordField, TextAreaField, validators
from compute import compute
from model import InputForm, InputForm1
app = Flask(__name__)
app.config['SECRET_KEY'] = 'Thisisasecret'
@app.route('/', methods=['GET', 'POST'])
def index():
form = InputForm(request.form)
form1 = InputForm1(request.form)
if form.validate_on_submit():
if request.method == 'POST':
r = form.r.data
t = form.t.data
u = form.u.data
s = compute(r,t,u)
else:
s = None
return render_template("view.html", form=form, form1=form1, s=s)
if form1.validate_on_submit():
if request.method == 'POST':
r1 = form1.r1.data
t1 = form1.t1.data
u1 = form1.u1.data
s1 = compute(r1,t1,u1)
else:
s1 = None
return render_template("view.html", form=form, form1=form1, s1=s1)
return render_template("view.html",form=form, form1=form1)
if __name__ == '__main__':
app.run(debug=True)
from flask_wtf import FlaskForm
from wtforms import validators, StringField, PasswordField,FloatField, validators
class InputForm(FlaskForm):
r = FloatField(label='var_r',default=0,validators=[validators.DataRequired()])
t = FloatField(label='var_t',default=0,validators=[validators.DataRequired()])
u = FloatField(label='var_u',default=0,validators=[validators.DataRequired()])
class InputForm1(FlaskForm):
r1 = FloatField(label='var_r1',default=0,validators=[validators.DataRequired()])
t1 = FloatField(label='var_t1',default=0,validators=[validators.DataRequired()])
u1 = FloatField(label='var_u1',default=0,validators=[validators.DataRequired()])
import math
def compute(r,t,u):
return (math.sin(r))* t + u
<form method="post" action="">
{{ form.csrf_token }}
{% for field in form %}
<dt>{{ field.name }}
<dd>{{ field|safe }} {{field.label }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}</ul>
{% endif %}</dd>
{% endfor %}
<p><input type=submit value=Compute0></form></p>
<h5> Valor: </h5>
<p>
{% if s != None %}
{{ s }}
{% endif %}
</p>
<form method="post" action="">
{{ form.csrf_token }}
{% for field in form1 %}
<dt>{{ field.name }}
<dd>{{ field|safe }} {{field.label }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}</ul>
{% endif %}</dd>
{% endfor %}
<p><input type=submit value=Compute1></form></p>
<h5> Valor: </h5>
<p>
{% if s1 != None %}
{{ s1 }}
{% endif %}
</p>
如果我理解你的描述,你在同一页面上有 2 个独立的表格 两者 将 POST
请求发送到 相同的视图函数 进行处理。
您想根据已提交的表单更新每个表单下方的 placeholder,我认为您需要执行 ajax
调用,因为(基于在上面的代码中)无法保留或保留其他形式的数据(例如数据库)
这样做:
- 更新表格代码
InputForm
由于 2 个表单具有相同的字段,您只需要一个用于此用例,然后调整和扩展具有不同字段集的其他表单的逻辑
from flask_wtf import FlaskForm
from wtforms.fields import FloatField, SubmitField
from wtforms.validators import DataRequired
class InputForm(FlaskForm):
r = FloatField('r', validators=[DataRequired()])
t = FloatField('t', validators=[DataRequired()])
u = FloatField('u', validators=[DataRequired()])
submit = SubmitField('Submit')
- 更新模板
<!-- the first form -->
<form class="form" id="form-1" method="POST" novalidate>
{{ form_1.csrf_token }}
<div class="row">
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_1.r.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_1.r(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_1.t.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_1.t(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_1.u.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_1.u(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
</div>
<div class="form-group row d-flex justify-content-between border bg-light p-3">
{{ form_1.submit(class="btn btn-sm btn-primary rounded-0 shadow-none") }}
<span class="placeholder">sin(r) * t + u = 0.00</span>
</div>
</form>
<!-- the second form -->
<form class="form" id="form-2" method="POST" novalidate>
{{ form_2.csrf_token }}
<div class="row">
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_2.r.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_2.r(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_2.t.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_2.t(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_2.u.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_2.u(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
</div>
<div class="form-group row d-flex justify-content-between border bg-light p-3">
{{ form_2.submit(class="btn btn-sm btn-primary rounded-0 shadow-none") }}
<span class="placeholder">sin(r) * t + u = 0.00</span>
</div>
</form>
在你的视图函数中(这里我只是隔离了 Blueprint
@bp
中的逻辑):
from flask import Blueprint, render_template, request, jsonify
from .forms import InputForm
from .utils import compute
bp = Blueprint(
'home',
__name__,
static_folder='static',
static_url_path='/home/static',
template_folder='templates',
# url_prefix=None,
# subdomain=None,
# url_defaults=None,
# root_path=None,
# cli_group=<object object>
)
@bp.route('/', methods=['GET', 'POST'])
def index():
form_1 = InputForm()
form_2 = InputForm()
if request.method == 'POST':
# we handle the "POST" request of the submitted "form_1"
if form_1.validate_on_submit():
r = form_1.r.data
t = form_1.t.data
u = form_1.u.data
s = compute(r,t,u)
return jsonify(s=s if s else 0, errors={})
else:
return jsonify(s=0, errors=form_1.errors)
# we handle the "POST" request of the submitted "form_2"
if form_2.validate_on_submit():
r = form_2.r.data
t = form_2.t.data
u = form_2.u.data
s = compute(r,t,u)
return jsonify(s=s if s else 0, errors={})
else:
return jsonify(errors=form_2.errors)
return render_template("home/index.html", form_1=form_1, form_2=form_2)
ajax
部分:
我建议你 如何利用 jinja2
模板继承来插入 locally a js
(与css
) 特定页面的块。
基于,我假设你正在使用 jquery
并且因为我们希望 jinja2
呈现此 javascript 行 url: "{{ url_for('home.index') }}",
所以在你的 template
中添加此代码
$(document).ready(function() {
"use strict";
$('.form').submit(function(e) {
e.preventDefault();
// get the id of the form currently submitted
let id = $(this).attr('id');
$.ajax({
url: "{{ url_for('home.index') }}",
type: 'POST',
cache: false,
dataType: 'json',
data: $('#' + id).serialize(), // serialize the form
success: function(data) {
// console.log(data);
// sanitize the form before processing the submitted fields
if( ! data.errors.hasOwnProperty('r')){
$('#' + id + ' input[name=r]').removeClass('is-invalid').next(".invalid-feedback").text('');
}
if( ! data.errors.hasOwnProperty('t')){
$('#' + id + ' input[name=t]').removeClass('is-invalid').next(".invalid-feedback").text('');
}
if( ! data.errors.hasOwnProperty('u')){
$('#' + id + ' input[name=u]').removeClass('is-invalid').next(".invalid-feedback").text('');
}
// @see
if( ! jQuery.isEmptyObject(data.errors)) { // Errors (data.errors = {})
console.log('Errors');
if(data.errors.hasOwnProperty('r')){
$('#' + id + ' input[name=r]').addClass('is-invalid').next(".invalid-feedback").text(data.errors['r']);
}
if(data.errors.hasOwnProperty('t')){
$('#' + id + ' input[name=t]').addClass('is-invalid').next(".invalid-feedback").text(data.errors['t']);
}
if(data.errors.hasOwnProperty('u')){
$('#' + id + ' input[name=u]').addClass('is-invalid').next(".invalid-feedback").text(data.errors['u']);
}
// update placeholder with the returned value
$('#' + id + ' .placeholder').html('sin(r) * t + u = ' + data.s);
} else { // Passed
console.log('Passed');
// get the submitted fields
let r = $('#' + id + ' input[name=r]').val();
let t = $('#' + id + ' input[name=t]').val();
let u = $('#' + id + ' input[name=u]').val();
// update placeholder with the returned value
$('#' + id + ' .placeholder').html('sin(' + r + ') * ' + t + ' + ' + u + ' = ' + data.s);
// reset fields
$('#' + id + ' input[name=r]').val('');
$('#' + id + ' input[name=t]').val('');
$('#' + id + ' input[name=u]').val('');
}
}
});
});
});
最后这个
希望这能解决您的问题。
如果默认值为“0”,则每个字段中的消息:“此字段为必填项”。 “compute0”和“compute1”上方有消息“csrf_token CSRF Token”。 只有 compute0 有效。
点击 compute0 显示结果。 单击 compute1 什么也没显示。
form 和 form1 有 3 个输入。 compute0 和 compute1 调用 (math.sin(r))* t + u.
from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import TextField, BooleanField, PasswordField, TextAreaField, validators
from compute import compute
from model import InputForm, InputForm1
app = Flask(__name__)
app.config['SECRET_KEY'] = 'Thisisasecret'
@app.route('/', methods=['GET', 'POST'])
def index():
form = InputForm(request.form)
form1 = InputForm1(request.form)
if form.validate_on_submit():
if request.method == 'POST':
r = form.r.data
t = form.t.data
u = form.u.data
s = compute(r,t,u)
else:
s = None
return render_template("view.html", form=form, form1=form1, s=s)
if form1.validate_on_submit():
if request.method == 'POST':
r1 = form1.r1.data
t1 = form1.t1.data
u1 = form1.u1.data
s1 = compute(r1,t1,u1)
else:
s1 = None
return render_template("view.html", form=form, form1=form1, s1=s1)
return render_template("view.html",form=form, form1=form1)
if __name__ == '__main__':
app.run(debug=True)
from flask_wtf import FlaskForm
from wtforms import validators, StringField, PasswordField,FloatField, validators
class InputForm(FlaskForm):
r = FloatField(label='var_r',default=0,validators=[validators.DataRequired()])
t = FloatField(label='var_t',default=0,validators=[validators.DataRequired()])
u = FloatField(label='var_u',default=0,validators=[validators.DataRequired()])
class InputForm1(FlaskForm):
r1 = FloatField(label='var_r1',default=0,validators=[validators.DataRequired()])
t1 = FloatField(label='var_t1',default=0,validators=[validators.DataRequired()])
u1 = FloatField(label='var_u1',default=0,validators=[validators.DataRequired()])
import math
def compute(r,t,u):
return (math.sin(r))* t + u
<form method="post" action="">
{{ form.csrf_token }}
{% for field in form %}
<dt>{{ field.name }}
<dd>{{ field|safe }} {{field.label }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}</ul>
{% endif %}</dd>
{% endfor %}
<p><input type=submit value=Compute0></form></p>
<h5> Valor: </h5>
<p>
{% if s != None %}
{{ s }}
{% endif %}
</p>
<form method="post" action="">
{{ form.csrf_token }}
{% for field in form1 %}
<dt>{{ field.name }}
<dd>{{ field|safe }} {{field.label }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}</ul>
{% endif %}</dd>
{% endfor %}
<p><input type=submit value=Compute1></form></p>
<h5> Valor: </h5>
<p>
{% if s1 != None %}
{{ s1 }}
{% endif %}
</p>
如果我理解你的描述,你在同一页面上有 2 个独立的表格 两者 将 POST
请求发送到 相同的视图函数 进行处理。
您想根据已提交的表单更新每个表单下方的 placeholder,我认为您需要执行 ajax
调用,因为(基于在上面的代码中)无法保留或保留其他形式的数据(例如数据库)
这样做:
- 更新表格代码
InputForm
由于 2 个表单具有相同的字段,您只需要一个用于此用例,然后调整和扩展具有不同字段集的其他表单的逻辑
from flask_wtf import FlaskForm
from wtforms.fields import FloatField, SubmitField
from wtforms.validators import DataRequired
class InputForm(FlaskForm):
r = FloatField('r', validators=[DataRequired()])
t = FloatField('t', validators=[DataRequired()])
u = FloatField('u', validators=[DataRequired()])
submit = SubmitField('Submit')
- 更新模板
<!-- the first form -->
<form class="form" id="form-1" method="POST" novalidate>
{{ form_1.csrf_token }}
<div class="row">
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_1.r.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_1.r(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_1.t.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_1.t(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_1.u.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_1.u(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
</div>
<div class="form-group row d-flex justify-content-between border bg-light p-3">
{{ form_1.submit(class="btn btn-sm btn-primary rounded-0 shadow-none") }}
<span class="placeholder">sin(r) * t + u = 0.00</span>
</div>
</form>
<!-- the second form -->
<form class="form" id="form-2" method="POST" novalidate>
{{ form_2.csrf_token }}
<div class="row">
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_2.r.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_2.r(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_2.t.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_2.t(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
<div class="col">
<div class="form-group row">
<div class="col-sm-3">
{{ form_2.u.label(class="col-form-label") }} <span class="text-danger">*</span>
</div>
<div class="col-sm-9">
{{ form_2.u(class="form-control rounded-0 shadow-none", **{"placeholder":"0"}) }}
<div class="invalid-feedback"></div>
</div>
</div>
</div>
</div>
<div class="form-group row d-flex justify-content-between border bg-light p-3">
{{ form_2.submit(class="btn btn-sm btn-primary rounded-0 shadow-none") }}
<span class="placeholder">sin(r) * t + u = 0.00</span>
</div>
</form>
在你的视图函数中(这里我只是隔离了 Blueprint
@bp
中的逻辑):
from flask import Blueprint, render_template, request, jsonify
from .forms import InputForm
from .utils import compute
bp = Blueprint(
'home',
__name__,
static_folder='static',
static_url_path='/home/static',
template_folder='templates',
# url_prefix=None,
# subdomain=None,
# url_defaults=None,
# root_path=None,
# cli_group=<object object>
)
@bp.route('/', methods=['GET', 'POST'])
def index():
form_1 = InputForm()
form_2 = InputForm()
if request.method == 'POST':
# we handle the "POST" request of the submitted "form_1"
if form_1.validate_on_submit():
r = form_1.r.data
t = form_1.t.data
u = form_1.u.data
s = compute(r,t,u)
return jsonify(s=s if s else 0, errors={})
else:
return jsonify(s=0, errors=form_1.errors)
# we handle the "POST" request of the submitted "form_2"
if form_2.validate_on_submit():
r = form_2.r.data
t = form_2.t.data
u = form_2.u.data
s = compute(r,t,u)
return jsonify(s=s if s else 0, errors={})
else:
return jsonify(errors=form_2.errors)
return render_template("home/index.html", form_1=form_1, form_2=form_2)
ajax
部分:
我建议你 jinja2
模板继承来插入 locally a js
(与css
) 特定页面的块。
基于,我假设你正在使用 jquery
并且因为我们希望 jinja2
呈现此 javascript 行 url: "{{ url_for('home.index') }}",
所以在你的 template
中添加此代码
$(document).ready(function() {
"use strict";
$('.form').submit(function(e) {
e.preventDefault();
// get the id of the form currently submitted
let id = $(this).attr('id');
$.ajax({
url: "{{ url_for('home.index') }}",
type: 'POST',
cache: false,
dataType: 'json',
data: $('#' + id).serialize(), // serialize the form
success: function(data) {
// console.log(data);
// sanitize the form before processing the submitted fields
if( ! data.errors.hasOwnProperty('r')){
$('#' + id + ' input[name=r]').removeClass('is-invalid').next(".invalid-feedback").text('');
}
if( ! data.errors.hasOwnProperty('t')){
$('#' + id + ' input[name=t]').removeClass('is-invalid').next(".invalid-feedback").text('');
}
if( ! data.errors.hasOwnProperty('u')){
$('#' + id + ' input[name=u]').removeClass('is-invalid').next(".invalid-feedback").text('');
}
// @see
if( ! jQuery.isEmptyObject(data.errors)) { // Errors (data.errors = {})
console.log('Errors');
if(data.errors.hasOwnProperty('r')){
$('#' + id + ' input[name=r]').addClass('is-invalid').next(".invalid-feedback").text(data.errors['r']);
}
if(data.errors.hasOwnProperty('t')){
$('#' + id + ' input[name=t]').addClass('is-invalid').next(".invalid-feedback").text(data.errors['t']);
}
if(data.errors.hasOwnProperty('u')){
$('#' + id + ' input[name=u]').addClass('is-invalid').next(".invalid-feedback").text(data.errors['u']);
}
// update placeholder with the returned value
$('#' + id + ' .placeholder').html('sin(r) * t + u = ' + data.s);
} else { // Passed
console.log('Passed');
// get the submitted fields
let r = $('#' + id + ' input[name=r]').val();
let t = $('#' + id + ' input[name=t]').val();
let u = $('#' + id + ' input[name=u]').val();
// update placeholder with the returned value
$('#' + id + ' .placeholder').html('sin(' + r + ') * ' + t + ' + ' + u + ' = ' + data.s);
// reset fields
$('#' + id + ' input[name=r]').val('');
$('#' + id + ' input[name=t]').val('');
$('#' + id + ' input[name=u]').val('');
}
}
});
});
});
最后这个
希望这能解决您的问题。