Here is an example implementation of this logic for working with the built-in functions of WTForms. The trick here is, if you want to use WTForms validation, you need to instantiate the form with any possible value, and then change the available options in Javascript to display the filtered values ββbased on another choice.
In this example, I'm going to use the concept of states and counties (I work with a lot of geodata, so this is the general implementation I'm building).
Here is my form, I have assigned unique identifiers to important elements to access them from Javascript:
class PickCounty(Form): form_name = HiddenField('Form Name') state = SelectField('State:', validators=[DataRequired()], id='select_state') county = SelectField('County:', validators=[DataRequired()], id='select_county') submit = SubmitField('Select County!')
Now in the "Checkbox" view for creating and processing the form:
@app.route('/pick_county/', methods=['GET', 'POST']) def pick_county(): form = PickCounty(form_name='PickCounty') form.state.choices = [(row.ID, row.Name) for row in State.query.all()] form.county.choices = [(row.ID, row.Name) for row in County.query.all()] if request.method == 'GET': return render_template('pick_county.html', form=form) if form.validate_on_submit() and request.form['form_name'] == 'PickCounty':
Kind of flask for answering XHR requests for counties:
@app.route('/_get_counties/') def _get_counties(): state = request.args.get('state', '01', type=str) counties = [(row.ID, row.Name) for row in County.query.filter_by(state=state).all()] return jsonify(counties)
And finally, javascript to place at the bottom of your Jinja template. I assume you mentioned Bootstrap that you are using jQuery. I also assume this is in the javascript line, so I use Jinja to return the correct URL for the endpoint.
<script charset="utf-8" type="text/javascript"> $(function() { // jQuery selection for the 2 select boxes var dropdown = { state: $('#select_state'), county: $('#select_county') }; // call to update on load updateCounties(); // function to call XHR and update county dropdown function updateCounties() { var send = { state: dropdown.state.val() }; dropdown.county.attr('disabled', 'disabled'); dropdown.county.empty(); $.getJSON("{{ url_for('_get_counties') }}", send, function(data) { data.forEach(function(item) { dropdown.county.append( $('<option>', { value: item[0], text: item[1] }) ); }); dropdown.county.removeAttr('disabled'); }); } // event listener to state dropdown change dropdown.state.on('change', function() { updateCounties(); }); }); </script>