flaskflask-wtforms

Using Flask and WTForms, a SelectField has a dictionary of {label: list} pairs. On submtting the form, how can label of chosen item be accessed?


I have a SelectField in a form made with Flask and WTFforms.

The SelectField is created with choices in a dictionary, {label:list}.

The problem is: because in some of the lists within this dictionary there are identical strings, I need a way to access the label to which the user's choice belongs to.

The following is paired down version within the views.py of my flask app, and doesn't include some things necessary for functionality.

from userClass import UserForm

@ bp.route('/', methods['GET', 'POST'])
def index():


    # initializing the form

    form1 = UserForm()


    # if selectProfile clicked

    if form1.selectProfile.data and form1.validate():
        data = form1.displayUserAge.data
            return data

The following is from my form.py.


userAge = {"Male": ["19-30y", "31-50y"], "Female": ["19-30y", "31-50y"]}

class UserForm(FlaskForm):
    displayUserAge = SelectField(u"Age", choices = userAge)

And here is the relevant section within the index.html using Jinjia:


{{ form1.hidden_tag() }}
{{ form1.displayUserAge.label }}
{{ form1.displayUserAge }}
{{ form1.selectProfile }}


Using form1.displayUserAge.data returns (for example) "19-30y", but does not indicate whether the user chooses Male or Female.

Using form1.displayUserAge.choices returns the all the choices but obviously does not indicate what the user chose.

One hack could be to make the choices more detailed and make a list of choices rather than a dictionary, i.e. ["Male 19-30y", "Male 31-50y", "Female 19-30y", "Female 31-50y"]. But this cluttered the dropdown menu.


Solution

  • In order to create a structure within the select field, <optgroup> elements are used whose labels cannot be accessed via the form object.

    It is possible to use two arguments for the embedded <option> elements, the first of which sets the value attribute and the second appears as text. To achieve this, it is necessary to assign lists of tuples within the dict. The gender can then be defined in the first value separated from the age by a separator.

    class UserForm(FlaskForm):
        age = SelectField(
            'Age', 
            choices={
                '': [('', 'Please select your age')], 
                'Female': [('f_19-30y', '19-30y'), ('f_31-50y', '31-50y')], 
                'Male': [('m_19-30y', '19-30y'), ('m_31-50y', '31-50y')], 
            }, 
            validators=[DataRequired()]
        )
    
    @app.route('/', methods=['GET', 'POST'])
    def index():
        form = UserForm(request.form)
        if form.validate_on_submit():
            gender, age = form.age.data.split('_', 1)
            print(gender, ' - ', age)
        return render_template('index.html', **locals())