8

データの状態に基づいて特定のボックスがチェックされた動的なチェックボックス リストを作成しようとしています。

これが私のフォームです:

class FooForm(Form):
    bar = SelectMultipleField(
        'Bar',
        option_widget=CheckboxInput(),
        widget=ListWidget(prefix_label=True))

コントローラーは次のとおりです。

@app.route('/fooform', methods = ['GET','POST'])
def foo():
    foos = foo_dao.find() 
    form = FooForm()
    form.bar.choices = [(foo.id, foo.label) for foo in foos]
    # SOMEHOW PRE-POPULATE CHECKBOXES HERE
    if form.is_submitted():
        # DO STUFF
    return render_template('foo.html', 
                           foos=foos,
                           form=form)

テンプレートは次のとおりです。

  <form action="" method="post" name="foos">
      {{form.bar}}
    <p><input type="submit" value="Add"></p>
  </form>

これによりチェックボックスリストが生成され、機能しますが、リスト内のどのチェックボックスを事前に入力するかを指定する方法がわかりません。

4

4 に答える 4

5

FormFieldとの組み合わせを使用してくださいFieldList: ボイラー プレートを少し余分に使用し、永続化の際に手でバインドする必要がありますが、提出物を複数のフィールドに分割することで、同様の結果を得ることができます。

これは、WTForms へのDRYerアプローチであることの利点です。これを順守すると、フォームがよりスムーズに機能することがわかります。これは、ライブラリに組み込まれているデフォルトの動作で作業しているためです。ライブラリでは Widget クラスを組み合わせて使用​​できますが、私の経験では、一緒にうまく機能する組み合わせのサブセットはかなり限られています。Field基本的な/Validatorの組み合わせに固執し、それらをFormField/で構成すると、FieldList物事ははるかにうまく機能します。

以下の例を参照してください。

コード

from collections import namedtuple
from wtforms import Form, FieldList, BooleanField, HiddenField, FormField
from webob.multidict import MultiDict

GroceryItem = namedtuple('GroceryItem', ['item_id', 'want', 'name'])

class GroceryItemForm(Form):
    item_id = HiddenField()
    want = BooleanField()

class GroceryListForm(Form):
    def __init__(self, *args, **kwargs):
        super(GroceryListForm, self).__init__(*args, **kwargs)

        # just a little trickery to get custom labels
        # on the list's checkboxes
        for item_form in self.items:
            for item in kwargs['data']['items']:
                if item.item_id == item_form.item_id.data:
                    item_form.want.label ='' 
                    item_form.label = item.name

    items = FieldList(FormField(GroceryItemForm))

item1 = GroceryItem(1, True, 'carrots')
item2 = GroceryItem(2, False, 'cornmeal')

data = {'items': [item1, item2]}

form = GroceryListForm(data=MultiDict(data))

print form.items()

生の HTML

<ul id="items">
   <li>
      carrots 
      <table id="items-0">
         <tr>
            <th></th>
            <td><input id="items-0-item_id
               " name="items-0-item_id" type="hidden" value="1"><input checked id="items-0-want" name="it
               ems-0-want" type="checkbox" value="y"></td>
         </tr>
      </table>
   </li>
   <li>
      cornmeal 
      <table id="items
         -1">
      <tr>
         <th></th>
         <td><input id="items-1-item_id" name="items-1-item_id" type="hidden" valu
            e="2"><input id="items-1-want" name="items-1-want" type="checkbox" value="y"></td>
      </tr>
      </t
      able>
   </li>
</ul>

レンダリング結果

ここに画像の説明を入力

form.dataPOST後の結果

{'items': [{'item_id': 1, 'want': True}, {'item_id': 2, 'want': False}]}

于 2014-06-01T14:22:02.073 に答える
2

内部サブクラスを使用したアプローチは、この問題に対して機能するはずです。

http://wtforms.simplecodes.com/docs/1.0.1/specific_problems.html#dynamic-form-composition

フォームを初期化する前に選択肢を設定する必要があります。これは、内部サブクラスで行うことができます。次に、フォームにオブジェクトを渡すことができます。これは、wtforms がフィールドに事前入力するために使用されます。

def foo():
    class F(FooForm):
        pass
    choices = [(foo.id, foo.label) for foo in foos]
    F.bar.choices = choices

    class MyObj(object):
        pass
    obj = MyObj()
    for choice in choices:
        setattr(obj, choice, True)

    form = F(request.POST or None, obj=obj)

これはテストされていませんが、うまくいくはずです。
幸運を!

于 2013-10-24T13:18:01.050 に答える