Dynamic Forms (Formsets) in Flask / WTForms?

与世无争的帅哥 提交于 2019-12-18 12:37:21

问题


In Django you have a multiple form feature called Formsets, which you can use to create multiple forms into the same template. I am trying to achieve something similar in Flask / WTforms.

<form action="{{ url_for('request-accept') }}" method='post'>           
   <table>
        <tbody>
            {% for request in requests %}
                    <tr>                    
                        <td>                        
                           <div class="person-header">
                              <img src="{{request.profile_pic_url}}" class="img-circle profile-image"/>
                              <p class="person-header-text">{{request.fullname()}}</p>    
                           </div>
                       </td>                
                       <td>
                           <input type="checkbox" id="{{request.key.urlsafe()}}" name="checkbox{{loop.index}}">
                       </td>                    
                   </tr>
           {% endfor %}
    </tbody>            
  </table>

  <input class='submit btn btn-primary' type=submit value="Connect">            
</form>

The idea is having one form that wrapps all the checkboxes, which the user like to tick to become friends with. As it currently stands I am not really generating any form class in Flask, since I don't know how to make a dynamic FormSet, hence I create the form dynamically inside the html.

The caveat is though, I don't know how to retrieve the selected user id via the checkbox. (I have stored it in the id because I didn't know better)

But I can't access the id in request.values['checkbox1']. I can only see if its on or off.

Any suggestions how to solve this please?


回答1:


The problem

Your problem is that id is not sent back to the server - only value is ... and since your checkboxes don't have a value attribute the default value is used, which happens to be on.

Since you tagged this with wtforms, I'll give you an example of how you could be doing this.

Never have this issue again

The WTForms' documentation has an example class that will create a list of checkboxes for you:

class MultiCheckboxField(SelectMultipleField):
    """
    A multiple-select, except displays a list of checkboxes.

    Iterating the field will produce subfields, allowing custom rendering of
    the enclosed checkbox fields.
    """
    widget = widgets.ListWidget(prefix_label=False)
    option_widget = widgets.CheckboxInput()

You would use this field in your custom form in this manner:

class FriendsForm(Form):
    potential_friends = MultiCheckboxField("Friends", coerce=int)

# ... later ...

@app.route("/add-friends", methods=["GET", "POST"])
def add_friends():
    form = FriendsForm(request.form)
    # lookup friends, for now we'll use a static list
    form.potential_friends.choices = [(1, "Sam"), (2, "Joe")]

    # We'll also need a mapping of IDs to Person instances
    # (Made up for this example - use your own ;-) )
    mapping = {
        1: Person("Sam", profile_pic="sam.jpg"),
        2: Person("Joe", profile_pic="joe.png")
    }

    if request.method == "POST":
        # Mark new friends

    return render_template("friends.html", form=form, persons=mapping)

Then, in friends.html you can iterate over the form.potential_friends field:

{% for person in form.potential_friends %}
    persons[person.data].profile_pic :: {{person.label}} :: {{person}}<br>
{% endfor %}

You can customize your HTML inside the for loop. My particular example should render (with a few more attributes, like for and name):

sam.jpg :: <label>Sam</label> :: <input type="checkbox" value="1">
joe.png :: <label>Joe</label> :: <input type="checkbox" value="2">



回答2:


I personnally would add a hidden input field in your fieldset under each checkbox with a name such as "friend_nametag1" and a value corresponding to the friend's ID. With the 1 being incremented for every "friend". You can thus look it up in flask view using something like

friend_list = []
list_of_checkboxes = ... (fetch from request.form... ?)
dict_of_friend_nametags = ... (build from request.form... ?)
if 'checkbox1' in list_of_checkboxes:
    friend_list.append(dict_of_friend_nametags.get('friend_nametag1')

Obviously you can use some sort of logic to have an incremental index (the "1" in "checkbox1" in this case).

I'm not too familiar with WTForms so there might be a better way to do this, but this solution is fairly straightforward to implement with your current code.

If you want a FieldSet or FormSet I would suggest you use the FormField in conjunction with the FieldList with the related docs here : http://wtforms.simplecodes.com/docs/dev/fields.html#field-enclosures

p.s.: I would not recommend using request as a variable name in your template or your code as it may shadow the global request of flask ? XD



来源:https://stackoverflow.com/questions/18188428/dynamic-forms-formsets-in-flask-wtforms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!