【问题标题】:SQLalchemy/wtforms update issue - 400 bad requestSQLalchemy/wtforms 更新问题 - 400 错误请求
【发布时间】:2025-12-02 08:30:01
【问题描述】:

我想要做的是,一旦用户提交了所有结果,我希望它根据我的过滤器更新 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))

【问题讨论】:

  • 您还没有包含您的@app.route 代码——您是在告诉它接受发布请求吗?例如@app.route('/eg/', methods=['post','get'])
  • 抱歉忘了在这里添加,但它在我的代码中

标签: python flask sqlalchemy jinja2


【解决方案1】:

问题是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. 

【讨论】:

  • filter_id 是从哪里来的?需要导入吗?
  • 稍等...将 filter_id 更改为 fixture_id
  • @Lorbat - 是的,这是一个错字 - 已修复 :-)
  • 如果是这样,那么这不应该工作吗? .update({'home_score':prediction.home_score.data\ ,'away_score':prediction.away_score.data})
  • @Lorbat - 是的,应该。
【解决方案2】:

根据flask docs,400 发生在:

如果表单属性中不存在键会怎样?在那里面 情况下会引发特殊的 KeyError。你可以像标准一样捕捉它 KeyError 但如果您不这样做,则会出现 HTTP 400 Bad Request 错误页面 而是显示。因此,对于许多情况,您不必处理 那个问题。

听起来 wtform 正在访问一个不在 multidict 中的键,从而引发了一个键错误。要对此进行测试,请使用 try/except 包装 validate 调用。 (我想,我认为这是发生关键错误的地方)。如果你发现异常,你就会得到答案。

【讨论】:

  • 对不起,我收到了 400 个错误请求,但我认为它是一样的。我的设置是一个 Flask,我所做的只是 redirect(url_for('predictions')) 这应该把它带回当前视图......所以它可能是别的东西?
最近更新 更多