How to make Flask-WTFoms update labels dynamically from list of label names?

Viewed 6567

I use WTForms to define form for data filtering it is defined like this (My goal is to have user specified labels for BooleanFields set, I let each user to name labels for fields and I save name of fields to Google Datastore):

class MainFilterForm(FlaskForm):
    """
    Represents main filter form.
    """

    start_date = pendulum.parse(
        str(pendulum.today().year)
        + str(pendulum.today().month)
        + '01')
    end_date = pendulum.today()
    calendar_colors_descriptions = CalendarColorsDescription(
        users.get_current_user().user_id()
        ).get_colors_description()
    search_query = StringField(
        'Search',
        [
            validators.Length(min=1, max=128),
            validators.optional()],
        default=None)
    start_date = DateField(
        'Start date',
        [validators.required()],
        format='%Y-%m-%d',
        default=start_date)
    end_date = DateField(
        'End date',
        [validators.required()],
        format='%Y-%m-%d',
        default=end_date)
    i_am_owner = BooleanField(
        'I am owner',
        default=False)
    include_all_day_events = BooleanField(
        'Include all day events',
        default=False)
    selected_colors_calendar_color = BooleanField(
        calendar_colors_descriptions[0],
        default=True)
    selected_colors_color1 = BooleanField(
        calendar_colors_descriptions[1],
        default=True)
    selected_colors_color2 = BooleanField(
        calendar_colors_descriptions[2],
        default=True)
    selected_colors_color3 = BooleanField(
        calendar_colors_descriptions[3],
        default=True)
    selected_colors_color4 = BooleanField(
        calendar_colors_descriptions[4],
        default=True)
    selected_colors_color5 = BooleanField(
        calendar_colors_descriptions[5],
        default=True)
    selected_colors_color6 = BooleanField(
        calendar_colors_descriptions[6],
        default=True)
    selected_colors_color7 = BooleanField(
        calendar_colors_descriptions[7],
        default=True)
    selected_colors_color8 = BooleanField(
        calendar_colors_descriptions[8],
        default=True)
    selected_colors_color9 = BooleanField(
        calendar_colors_descriptions[9],
        default=True)
    selected_colors_color10 = BooleanField(
        calendar_colors_descriptions[10],
        default=True)
    selected_colors_color11 = BooleanField(
        calendar_colors_descriptions[11],
        default=True)

CalendarColorsDescription class returns list of strings which represents desired labels for Boolean fields (these values are stored in Google Datastore).

This form is displayed on dashboard home page rendered by Jinja2 and Flask (only relevant part of Flask class is pasted here):

@APP.route('/dashboard', methods=('GET', 'POST'))
def dashboard():
    """
    Main page handler, shows stats dashboard.
    """

    form = MainFilterForm()
    calendar_events = get_events(
        calendar_service,
        form.search_query.data,
        form.start_date.data,
        form.end_date.data,
        form.i_am_owner.data,
        form.include_all_day_events.data,
        form.selected_colors_calendar_color.data,
        form.selected_colors_color1.data,
        form.selected_colors_color2.data,
        form.selected_colors_color3.data,
        form.selected_colors_color4.data,
        form.selected_colors_color5.data,
        form.selected_colors_color6.data,
        form.selected_colors_color7.data,
        form.selected_colors_color8.data,
        form.selected_colors_color9.data,
        form.selected_colors_color10.data,
        form.selected_colors_color11.data)
    return flask.render_template(
        'dashboard.html',
        calendar_events=calendar_events,
        form=form)

On first run all labels are properly set and displayed. But when I change values in Datastore (via another form), values in form labels are never updated they stays the same, unless I restart webserver.

I tried to put "debug" print to different parts of program and output the class which reads data from Datastore, and output is always valid and in sync with expected values. It seems to me (and for me it is total magic), that

form = MainFilterForm()

is executed only once at first HTTP request (as i tried to put "debug" print to MainFilterForm definition as well, but this print was shown only at first HTTP request).

I tried to set labels manually with:

form.selected_colors_calendar_color.label = calendar_colors_descriptions[0]

after line:

form = MainFilterForm()

But I got error "TypeError: 'str' object is not callable" from, i believe, Jinja2.

2 Answers

Create a sample form as follows:

from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired, Length
from wtforms.fields import Label  #<==This is the key

#in forms.py
class MyForm(FlaskForm):
    name = StringField('Your Name', validators=[DataRequired(), Length(min=2, max=20)])
    submit = SubmitField('Sign Up')

#in route.py
from forms import MyForm
#initialize your app

@app.route("/some-test-route", methods = ["GET","POST"])
def someTestRoute():
    form = MyForm
    if some condition:
        #change the label as follows.
        form.name.label = Label(field_id = "name", text = "Your New Field Description Goes Here.")
        #The above line creates the following lable object
        #<label for="name">Your New Field Description Goes Here.</label>
        #which replaces the current label object that is
        #<label for="name">yourname</label>
    if form.validate_on_submit():
        #do something
        return redirect(url_for(endpoint = "someEndPoint"))
    return render_template("WhereEverYour_MyForm_Template.html")
Related