SQLalchemy/wtforms 更新问题 - 400 错误请求

0 投票
2 回答
820 浏览
提问于 2025-04-18 09:07

我想做的是,当用户提交所有结果后,我希望根据我的筛选条件更新 Fixture_prediction 模型。不过我得到的却是 400 错误请求。日志没有提供足够的信息让我知道哪里出错了。有没有什么想法?

我觉得这可能和通过表单提交的元组数据有关……

表单显示得很好,只是在我提交表单时,它直接返回了错误请求。

我的错误

Bad Request

The browser (or proxy) sent a request that this server could not understand.

我目前的情况:

视图

@app.route('/predictor/',methods=['GET','POST'])
@login_required
def predictions():
    user_id = g.user.id
    # retrieve predictions
    prediction= db.session.query(Fixture_prediction,\
                Fixture_prediction.fixture_id,Fixture.stage,\
                Fixture.home_team,Fixture_prediction.home_score,\
                Fixture_prediction.away_score,Fixture.away_team)\
                .outerjoin(Fixture,Fixture.id==Fixture_prediction.fixture_id)\
                .outerjoin(User,Fixture_prediction.user_id == User.id)\
                .filter(Fixture_prediction.fixture_id==Fixture.id)\
                .filter(Fixture_prediction.user_id==user_id).all()
    data = {'predictions': prediction}
    form = PredictionListForm(data=MultiDict(data))
    if request.method == 'POST':
        if form.validate() == False:
            flash('A score is missing, please fill in all predictions')
            render_template('predictor.html', form=form)
        else:
            #for pred in prediction:
            store=Fixture_prediction.query\
                            .filter_by(user_id=user_id)\
                            .filter_by(fixture_id=request.form['fixture_id'])\
                            .update({'home_score':request.form['home_score']\
                                    ,'away_score':request.form['away_score']})
            db.session.commit()
            flash('Prediction added')
            return redirect(url_for("predictions"))
    # display current predictions
    elif request.method == 'GET':
        return render_template('predictor.html', form=form)

模板

{% extends "base.html" %}

{% block content %}

  <h1>Predictions</h1>
  <p></p>
  <p>Please make your predictions here</p>
  <form action='' method='post'>
    {{form.predictions()}}
    <p><input type="submit" value="Submit Predictions"></p>
   </form>

{% endblock %}

表单

class PredictionForm(WTForm):
    fixture_id = fields.IntegerField(validators=[validators.required()])
    stage = fields.TextField(validators=[validators.required()])
    home_team = fields.TextField(validators=[validators.required()])
    home_score = fields.IntegerField(validators=[validators.required()])
    away_score = fields.IntegerField(validators=[validators.required()])
    away_team = fields.TextField(validators=[validators.required()])

class PredictionListForm(WTForm):
    predictions = FieldList(FormField(PredictionForm))

2 个回答

0

根据Flask的文档,当出现400错误时,通常是因为:

如果在表单属性中找不到某个键,会发生什么呢?在这种情况下,会抛出一个特殊的KeyError错误。你可以像处理普通的KeyError那样捕获它,但如果你不这样做,就会显示一个HTTP 400错误页面。所以在很多情况下,你不需要特别处理这个问题。

听起来像是wtform在访问一个不在多字典中的键,从而引发了KeyError。为了测试这个,可以用try/except来包裹validate调用。(我觉得,我猜想这个地方可能会出现KeyError)。如果你捕获到了这个异常,那你就找到了答案。

2

问题在于,request.form中没有fixture_id这个字段。这会导致底层的MultiDict抛出一个KeyError错误,而Flask会把这个错误转换成400错误。

没有fixture_id的原因是你使用了FieldListFormField这两个字段封装器,它们会改变你提供给WTForms的字段名称,以避免名称冲突。

解决方法很简单,就是直接使用你已有的form实例来访问数据(因为WTForms已经为你做好了映射):

# in your else clause
for prediction in form.predictions:
    store = Fixture_prediction.query \
                              .filter_by(user_id=user_id) \
                              .filter_by(fixture_id=prediction.fixture_id.data)
    # etc. 

撰写回答