-
-
Save ectrimble20/468156763a1389a913089782ab0f272e to your computer and use it in GitHub Desktop.
| {% extends "layout_new.html" %} | |
| {% block content_main %} | |
| <div class="content-section"> | |
| <form method="POST" action=""> | |
| {{ form.hidden_tag() }} | |
| <fieldset class="form-group"> | |
| <legend class="border-bottom mb-4">User Choices</legend> | |
| {% if form.choices.errors %} | |
| <div class="invalid-feedback"> | |
| {% for error in form.choices.errors %} | |
| <span>{{ error }}</span> | |
| {% endfor %} | |
| </div> | |
| {% endif %} | |
| {% for choice in form.choices %} | |
| <div class="form-check"> | |
| {{ choice(class="form-check-input") }} | |
| {{ choice.label(class="form-check-label") }} | |
| </div> | |
| {% endfor %} | |
| </fieldset> | |
| <div class="form-group"> | |
| {{ form.submit(class="btn btn-outline-info") }} | |
| </div> | |
| </form> | |
| </div> | |
| {% endblock content_main %} |
| class MultiCheckboxField(SelectMultipleField): | |
| widget = widgets.ListWidget(prefix_label=False) | |
| option_widget = widgets.CheckboxInput() | |
| class ExampleForm(FlaskForm): | |
| choices = MultiCheckboxField('Routes', coerce=int) | |
| submit = SubmitField("Set User Choices") |
| @example.route("/example", methods=["GET", "POST"]) | |
| def example(): | |
| form = ExampleForm() | |
| # populate the forms dynamically with the choices in the database | |
| form.check_options.choices = [(c.id, c.desc) for c in Choices.query.all()] | |
| # if it's a post request and we validated successfully | |
| if request.POST and form.validate_on_submit(): | |
| # get our choices again, could technically cache these in a list if we wanted but w/e | |
| c_records = Choices.query.all() | |
| # need a list to hold our choices | |
| accepted = [] | |
| # looping through the choices, we check the choice ID against what was passed in the form | |
| for choice in c_records: | |
| # when we find a match, we then append the Choice object to our list | |
| if choice.id in form.check_options.data: | |
| accepted.append(choice) | |
| # now all we have to do is update the users choices records | |
| user.choices = accepted | |
| db.session.add(user) | |
| db.session.commit(user) | |
| else: | |
| # tell the form what's already selected | |
| form.choices.data = [c.id for c in user.choices] | |
| return render_template('example.html', form=form) | |
| user_choices = app_db.Table('user_choices', | |
| app_db.Column('user_id', app_db.Integer, app_db.ForeignKey('user.id'), primary_key=True), | |
| app_db.Column('choice_id', app_db.Integer, app_db.ForeignKey('choice.id'), primary_key=True) | |
| ) | |
| class User(db.Model, UserMixin): | |
| id = app_db.Column(app_db.Integer, primary_key=True) | |
| # other stuff as required | |
| choices = db.relationship('Choices', secondary=user_choices, lazy='subquery' | |
| backref=db.backref('users_choice', lazy=True)) | |
| class Choices(db.Model): | |
| id = app_db.Column(app_db.Integer, primary_key=True) | |
| desc = app_db.Column(app_db.String(25), nullable=False) |
This is very helpful, thanks
Hi, thanks for the example. One thing I can't fully comprehend is: where did that form.check_options.choices come from? It looks like it should've been belong to the form.py but I can't quite figure out how. Could you please elaborate?
Hi, thanks for the example. One thing I can't fully comprehend is: where did that
form.check_options.choicescome from? It looks like it should've been belong to the form.py but I can't quite figure out how. Could you please elaborate?
Had to go dig around in my old code to figure out what was going on here as I haven't touched this code in quite some time, I think check_options is a typo or a renaming that didn't make it throughout the example. I believe it's actually suppose to be form.choices.choices based on the ExampleForm class as it's suppose to be reference to the selected options from the forms MultiCheckboxField which is choices = MultiCheckboxField('Routes', coerce=int) in the example code. Thinking about it now, chances are when I was copying the code to make this little reference, I changed the name from choices.choices to check_options.choices because it looked weird with choices.choices.
A more complete example is in my FlaskProductSiteDemo repo on Github. The domain/admin/routes.py and domain/admin/forms.py has a clearer naming example that doesn't have a random name appear out of the blue.
I believe it's actually suppose to be
form.choices.choicesbased on the ExampleForm class as it's suppose to be reference to the selected options from the forms MultiCheckboxField which ischoices = MultiCheckboxField('Routes', coerce=int)in the example code. Thinking about it now, chances are when I was copying the code to make this little reference, I changed the name fromchoices.choicestocheck_options.choicesbecause it looked weird withchoices.choices.
I guess that makes sense, yeah. Thanks for the quick reply.
A more complete example is in my FlaskProductSiteDemo repo on Github. The
domain/admin/routes.pyanddomain/admin/forms.pyhas a clearer naming example that doesn't have a random name appear out of the blue.
I'll definitely check it.
Very useful, thank you!
This was helpful. Thanks!
Can't say enough about how much this helped me! As a note to others, I had to import "widgets" from wtforms.
# tell the form what's already selected
form.choices.data = [c.id for c in user.choices]Thanks! 👍
Very valuable. Thanks a lot!
How to set attributes (key and value) to each checkbox?
Sorry to anyone who stumbles on this, I didn't include imports or any fluff. This is some example code I'm jotting down for my own reference which handles multiple selections using check boxes since isn't a good solution for all options in which you wish to assign certain values (e.g a User Access Control setup where you want to check off allowed actions for a specific user). Note that a lot of this was C&P from a demo project I'm doing with Flask, so some names might be incorrect and the code might not function 100% out of the box, but if anything, I hope this helps anyone who was stuck on this problem as I was.