问题
What I'm trying to do is, once the user submits all the results I want it to update the Fixture_prediction model according to my filters. Although what I get is 400 bad request. The log doesnt tell me enough to know whats going wrong. Any ideas?
I think its to do with the tuple data submitted through the form...
The form displays fine its just when I submit the form it goes straight to a bad request.
my error
Bad Request
The browser (or proxy) sent a request that this server could not understand.
What I have currently:
views
@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)
template
{% 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 %}
forms
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))
回答1:
The problem is that there is no field fixture_id
in request.form
. This results in a KeyError
being raised by the underlying MultiDict, which is translated into a 400 by Flask.
The reason there is no fixture_id
is because you are using the field enclosures FieldList
and FormField
both of which alter the names you provide to WTForms to avoid collisions.
The fix is to simply use the form
instance that you have to access the data (as WTForms has already mapped it for you):
# 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.
回答2:
According to the flask docs, a 400 occurs when:
What happens if the key does not exist in the form attribute? In that case a special KeyError is raised. You can catch it like a standard KeyError but if you don’t do that, a HTTP 400 Bad Request error page is shown instead. So for many situations you don’t have to deal with that problem.
It sounds like the wtform is accessing a key that is not in the multidict, raising a keyerror. To test this, wrap the validate call with a try/except. (I think, I'd assume this is where the keyerror occurs). If you catch the exception, you'll have your answer.
来源:https://stackoverflow.com/questions/24119873/sqlalchemy-wtforms-update-issue-400-bad-request