Radim J Radim J - 3 years ago 180
Python Question

validate_on_submit() fails when RadioButton choices are dynamically generated

I am creating quiz-like web application for learning languages using Flask, Jinja, WTForms, SqlAlchemy etc. Once an user completes such a language course by successfully going through all levels stored in JSON file I want the app offer him a practice mode, where the user will answer randomly selected levels.

When I run the app, I can see radio buttons generated with values from random level as I want, but when I choose any answer and submit it, form.validate_on_submit() returns False and form.errors returns {'practiceform': [u'Not a valid choice']}. When I hard-code value to currentLevel variable, it works properly.

views.py

@user_blueprint.route('/courses/<course>/quiz/practice',methods=['GET','POST'])
@login_required
def practice(course):
courseClass = class_for_name("project.models", course.capitalize())
courses = courseClass.query.filter_by(email=current_user.email).first()
maxLevel = courseClass.query.filter_by(email=current_user.email).first().get_maxLevel()
currentLevel = randint(0, maxLevel-1) # If this value is hard-coded or fetched from db, it works correctly

dic = generateQuestion(course, currentLevel)
display = dic["display"]
correct = dic["correct"]
options = dic["options"]

form = PracticeForm(request.form)
form.practiceform.choices = [(option, option) for option in options]


if form.validate_on_submit():
practiceForm = form.practiceform.data

if ((practiceForm == correct) and courses):
# Do something
flash("Nice job", 'success')
return redirect(url_for('user.practice', course=course))

else:
# Do something else
flash("Wrong answer", 'danger')
return redirect(url_for('user.practice', course=course))

return render_template('courses/practice.html', form=form, display=display)


forms.py

class PracticeForm(Form):

practiceform = RadioField('practice')


practice.html

{% extends "_base.html" %}
{% block content %}

<form action='' method='POST' role='form'>
<p>
<!-- Tried put form.csrf, form.csrf_token, form.hidden_tag() here -->
{{ form.practiceform() }}
</p>
<input type="submit" value="submit" />
</form>
{% endblock %}


So what am I missing there? What makes difference between lets say hardcoded level 25, which works properly or if the number 25 is randomly generated within randint?

Answer Source

So I found that randint() caused the problem because the practice(course) method was called on both GET and POST actions which led to having two different integers -> two different forms most of the time. So I refactored the code. kept the practice(course) method for GET action and created a new method which handles POST action and this solved the problem.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download