I am working on building a small survey system to meet some specific requirements for a research project I'm working on. One of those requirements is the user has to be able to save their place and be able to return to the survey later and finish their work.
I am using Flask and Flask-WTF to make this system, and I'm using a MySQL database to save the users' responses. I've run into an issue where I am not able to have default values when using a FieldList of RadioFields, where my goal is to dynamically set this default value for the questions that have been answered to allow the user to see/modify their previous work.
Here are the forms I've built, the html template, and the current output:
class Phrase(db.Model):
__tablename__ = 'phrases'
id = db.Column(db.Integer, primary_key=True, nullable=False)
phrase_text = db.Column(db.Text, nullable=False)
...
class SinglePhraseForm(Form):
phrase_rating = RadioField()
phrase_cat = SelectField("Please choose whether this phrase is more useful in written or spoken communication:", choices=[('w', 'Written'), ('s', 'Spoken')])
class AllPhrasesForm(FlaskForm):
phrases = FieldList(FormField(SinglePhraseForm), min_entries=5)
...
@app.route("/phrases", methods=["GET", "POST"])
def phrases():
phrases_query = Phrase.query.all()
form = AllPhrasesForm()
for i in range(len(phrases_query)):
form.phrases[i].phrase_rating.label = f"Please rate how useful the following phrase is: {phrases_query[i].phrase_text}"
form.phrases[i].phrase_rating.choices = [('1', '1 - Not useful'), ('2','2'), ('3','3'), ('4','4'), ('5','5 - Very Useful')]
form.phrases[i].phrase_rating.default = str((i % 5) + 1)
### THIS CODE WORKS AND RENDERS DEFAULT CORRECTLY ###
# form = SinglePhraseForm()
# form.phrase_rating.label = "THIS IS A TEST LABEL"
# form.phrase_rating.choices = [('t1', 'TEST1'), ('t2', 'TEST2'), ('t3', 'TEST3')]
# form.phrase_rating.default = 't2'
# form.process()
if form.validate_on_submit():
if form.continue_survey.data:
return redirect(url_for("extended_responses"))
return render_template("phrases.html", form=form)
<h1>Phrases</h1>
<form method="POST" action="/phrases">
{{ form.hidden_tag() }}
{% for phrase in form.phrases %}
{% for subfield in phrase if subfield.widget.input_type != "hidden" %}
<tr>
<td>{{ subfield.label }}</td>
<td>{{ subfield() }}</td>
</tr>
{% endfor %}
<br>
{% endfor %}
<!-- TEST FOR SINGLE FORM -->
<!-- {% for subfield in phrase if subfield.widget.input_type != "hidden" %}
<tr>
<td>{{ subfield.label }}</td>
<td>{{ subfield() }}</td>
</tr>
{% endfor %} -->
</form>
In the phrases route, I am trying to iterate over the RadioFields and dynamically set their label, choices, and default values. The label and choices correctly render, but the default value is not showing up:
Screenshot of the first two questions with dummy data. I've tried following answers like this one, but using form.process()
simply removes all of my dynamic values: Screenshot of the form after using form.process(), which is not what I want.
I tried exploring using my SinglePhraseForm (changing the base class from Form to FlaskForm) and am actually able to get all the values in the commented out code to render, including default, using form.process()
and the commented out code in the html template. This makes me things I'm doing something wrong with the FieldList.
Any guidance on how I can correctly render dynamic default values for this FieldList of RadioFields?