Flask/WTForms中的动态表单(Formsets)是什么?

5
在Django中,有一个名为Formsets的多表单特性,可以用来在同一模板中创建多个表单。我正在尝试在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>

这个想法是拥有一个包含所有复选框的表单,用户可以勾选以成为朋友。目前我在Flask中没有生成任何表单类,因为我不知道如何制作动态FormSet,因此我在html内部动态创建表单。
但是问题在于,我不知道如何通过复选框检索所选的用户ID。(我将其存储在id中,因为我不知道更好的方法)
但是我无法访问request.values ['checkbox1']中的id。我只能看到它是打开还是关闭。
请问有什么解决方法吗?
2个回答

11

问题

您的问题在于,服务器没有收到id,而只有value……由于您的复选框没有value属性,因此使用默认值on

既然您标记了这个问题为,我会给您举一个例子,告诉您如何做到这一点。

再也不要遇到这个问题了

WTForms的文档中有一个示例类,可以为您创建复选框列表

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()
您将在您的自定义表单中使用此字段,步骤如下:
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)

然后,在friends.html页面中,您可以遍历form.potential_friends字段:

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

您可以在 for 循环中自定义HTML。我的特定示例应该呈现(带有更多的属性,比如forname):

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

选项需要放入MultiCheckboxField中: 将form.choices = ...更改为form.potential_friends.choices = ... - stefanjunker
@stefanjunker - 是的,那确实是个笔误 - 现在已经修正了!感谢您帮助改进问题! - Sean Vieira

0
我个人会在每个复选框下的 fieldset 中添加一个名为“friend_nametag1”的隐藏输入字段,其值对应于朋友的 ID。其中 1 会随着每个“朋友”而递增。因此,您可以使用类似以下的方式在 Flask 视图中查找它:
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')

显然,您可以使用某种逻辑来具有增量索引(在此情况下,“checkbox1”中的“1”)。

我对WTForms不太熟悉,因此可能有更好的方法来解决这个问题,但是使用当前代码实现这个解决方案相当简单。

如果您想要一个FieldSet或FormSet,我建议您使用FormField与FieldList结合使用,相关文档在此处:http://wtforms.simplecodes.com/docs/dev/fields.html#field-enclosures

p.s.:我不建议在模板或代码中使用request作为变量名,因为它可能会遮盖flask的全局request ? XD


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接