技術

Django フォームセットで制御フィールドを不可視にする

イキナリ関係無い話ですが、フォームセットの事を最初は「複数種類の」フォームをまとめて扱えるものと思い込んでいました。
本当は「1種類のフォームを複数」まとめて扱えるものです。
これでちょっと時間を無駄にしました。みなさんもお気をつけ下さい。(そんな勘違いする人はいないかw)

さて本題です。
フォームセットは例えば以下のように生成できます。

from django import forms
from django.forms.formsets import formset_factory

class TestForm(forms.Form):
    title = forms.CharField(label = u'タイトル')

TestFormSet = formset_factory(TestForm)

TestFormSetはクラスなので、ビューのコードとかでTestFormSet()とやると実際に使えるようになるわけです。
で、フォームセットには色々と便利な機能がありまして、その中に順序と削除フラグを指定するためのフィールドを追加する機能があります。
以下のようにフォームセットクラスを生成してる部分をちょっと変えるだけです。

TestFormSet = formset_factory(TestForm, can_order = True, can_delete = True)

こうすると、ページでフォームが表示される場合に、各レコードに追加で順序のためのinput[type=text]と削除フラグのためのinput[type=checkbox]が追加で表示されます。
もちろん表示するだけじゃなくてこれらの制御フィールドのデータがポストされたときに、フォームセットでいい感じに操作出来るわけです。

便利な機能ではありますが、制御用のフィールドがもろ出しなので、エンドユーザー用のページでは主に見た目の問題からそのまま使うってのはあまり出来ないでしょう。
(そもそもそういう場面で使うことは想定されてないらしいです。)

そういう場合は制御フィールドをユーザーに直接見せずに、JavaScriptでいい感じに制御してあげるのが、よくあるパターンだと思います。
フォームセットの利便性を活かしつつそうするためには、テンプレートでゴリゴリと頑張るとか、CSSやJavaScriptで頑張るとかが考えられますが、そもそも制御フィールドがhiddenで出力されてくれれば何の問題も無いわけです。

で、以下のようにやってみたらうまい具合に行きました。(Django v1.2)

from django import forms
from django.forms.formsets import BaseFormSet, ORDERING_FIELD_NAME, DELETION_FIELD_NAME, formset_factory

class TestForm(forms.Form):
    title = forms.CharField(label = u'タイトル')

class HiddenControlFormSet(BaseFormSet):
    def add_fields(self, form, index):
        u"""制御用フィールドを不可視にする"""
        BaseFormSet.add_fields(self, form, index)
        if ORDERING_FIELD_NAME in form.fields:
            form.fields[ORDERING_FIELD_NAME].widget = forms.HiddenInput()
        if DELETION_FIELD_NAME in form.fields:
            form.fields[DELETION_FIELD_NAME].widget = forms.HiddenInput()

TestFormSet = formset_factory(TestForm,
    formset = HiddenControlFormSet,
    can_order = True,
    can_delete = True,
)

BaseFormSetクラスを継承したHiddenControlFormSetクラスを作りadd_fieldメソッドをオーバーライドし、そのクラスをformset_factoryに指定してるだけです。

コメントを残す

メールアドレスが公開されることはありません。



※画像をクリックして別の画像を表示

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください