为什么 Flask 似乎需要在 POST 之后重定向?

问题描述 投票:0回答:1

我有一系列想要在称为粉丝的烧瓶蓝图中呈现的表单。 我在开发期间使用 sqlalchemy 到 SQLLite 来保存数据并使用 Flask-wtforms 进行渲染。 问题似乎出在 DecimalRangeField 上 - 如果我有两个或更多风扇并仅更改其中一个上的滑块,则另一个滑块似乎会移动以匹配它,尽管 DecimalRangeField 的数据值保持不变。 注意:下面的代码正在运行,当我在下面突出显示的重定向行被删除时,就会出现问题。

这是添加了重定向“修复”的routes.py代码:

@bp.route('/', methods=['GET', 'POST'])
def fans_index():
    fans = Fan.query.all()
    if fans.__len__() == 0:
      return redirect(url_for('fans.newfan'))
    form = FanForm(request.form)
    if form.validate_on_submit(): # request.method == 'POST'
      for fan in fans:
        if fan.name == form.name.data:
          fan.swtch = form.swtch.data
          fan.speed = round(form.speed.data)
          db.session.commit()
      return redirect(url_for('fans.fans_index')) # <-- THIS is required, why?
    else: # request.method == 'GET'
      pass
    forms = []
    for fan in fans:
      form = FanForm()
      form.name.data = fan.name
      form.swtch.data = fan.swtch
      form.speed.data = fan.speed
      forms.append(form)
    return render_template('fans_index.html', title='Fans!', forms=forms)

这里是使用的表格:

class FanForm(FlaskForm):
    name = HiddenField('Name')
    swtch = BooleanField('Switch', render_kw={'class': 'swtch'})
    speed = DecimalRangeField('Speed', render_kw={'class': 'speed'}, validators=[DataRequired()])
    submit = SubmitField('Save Fan')

这是 html 模板:

<h1>Fans</h1>
<div class="container">
    <div class="row">
        {% for form in forms %}
        <div class="col mx-1 shadow-5-strong border border-white rounded" style="max-width: 220px">
            <h2 class="ms-1">{{ form.name.data }}:</h2>
            <form class="mx-auto ms-3" name="{{ form.name.data }}" action="" method="post">
                {{ form.hidden_tag() }}
                <div>{{ form.name }}</div> 
                <p>
                    {{ form.speed.label }}: <span class="speed_display_val">{{ form.speed.data | round }}%</span><br>
                    {{ form.speed(min=20) }}<br>
                    {% for error in form.speed.errors %}
                    <span style="color: red;">[{{ error }}]</span>
                    {% endfor %}
                </p>
                <p>
                  {{ form.swtch.label }} <span class="ms-3">{{ form.swtch }}</span><br>
                  {% for error in form.swtch.errors %}
                  <span style="color: red;">[{{ error }}]</span>
                  {% endfor %}
                </p>
                <p>{{ form.submit }}</p>
            </form>
        </div>
        {% endfor %}
    </div>
</div>

我还为此页面提供了一些简单的 JavaScript,用于为滑块设置动画,并在用户移动滑块或单击用于打开和关闭风扇的复选框时进行提交:

/* script to animate the slider value changing and post data on slider mouseup or switch click */
const values = Array.from(document.getElementsByClassName('speed_display_val'));
const speeds = Array.from(document.getElementsByClassName('speed'));
const swtches = Array.from(document.getElementsByClassName('swtch')); //Note: switch is a reserved word in JS

speeds.forEach((speed, i) => {
  speed.oninput = (e) => { values[i].textContent = Math.round(e.target.value) + '%' };
  speed.onmouseup = () => { speed.form.requestSubmit() };
});
swtches.forEach((swtch) => {
  swtch.onclick = () => { swtch.form.requestSubmit() };
});
python flask flask-sqlalchemy flask-wtforms
1个回答
0
投票

FlaskForm
将自动使用
flask.request.form
flask.request.files
中的值。要解决此问题,您可以传递
None
作为表单的
formdata
属性。这样,就不再需要重置
flask.request.form
的重定向了。

您的代码将如下所示。

@bp.route('/', methods=['GET', 'POST'])
def fans_index():
    if Fan.query.count() == 0:
        return redirect(url_for('.newfan'))
    
    form = FanForm(request.form)
    if form.validate_on_submit():
        fan = Fan.query.filter_by(name=form.name.data).first()
        fan.swtch = form.swtch.data
        fan.speed = round(form.speed.data)
        db.session.commit()

    forms = [FanForm(formdata=None, obj=fan) for fan in Fan.query.all()]
    return render_template('fans_index.html', **locals())
© www.soinside.com 2019 - 2024. All rights reserved.