フォームセット
- class BaseFormSet
フォームセットは、同じページ上の複数のフォームを操作するための抽象化レイヤーです。 データグリッドと比較するのが最適です。 次のフォームがあるとします。
ユーザーが一度に複数の記事を作成できるようにすることができます。 ArticleForm
からフォームセットを作成するには、次のようにします。
これで、ArticleFormSet
という名前のフォームセットクラスが作成されました。 フォームセットをインスタンス化すると、フォームセット内のフォームを反復処理して、通常のフォームの場合と同じように表示することができます。
ご覧のとおり、空のフォームは1つしか表示されていません。 表示される空のフォームの数は、extra
パラメーターによって制御されます。 デフォルトでは、 formset_factory()は1つの追加フォームを定義します。 次の例では、2つの空白のフォームを表示するフォームセットクラスを作成します。
フォームセットを反復処理すると、フォームは作成された順序でレンダリングされます。 __iter__()
メソッドの代替実装を提供することにより、この順序を変更できます。
フォームセットにインデックスを付けることもできます。これにより、対応するフォームが返されます。 __iter__
をオーバーライドする場合、動作を一致させるには、__getitem__
もオーバーライドする必要があります。
フォームセットでの初期データの使用
初期データは、フォームセットの主なユーザビリティを推進するものです。 上に示したように、追加のフォームの数を定義できます。 これが意味するのは、初期データから生成されるフォームの数に加えて、表示する追加のフォームの数をフォームセットに指示しているということです。 例を見てみましょう:
現在、上記の合計3つのフォームがあります。 1つは渡された初期データ用で、2つは追加のフォームです。 また、初期データとして辞書のリストを渡していることにも注意してください。
フォームセットの表示にinitial
を使用する場合は、フォームセットの送信を処理するときに同じinitial
を渡して、ユーザーが変更したフォームをフォームセットが検出できるようにする必要があります。 たとえば、ArticleFormSet(request.POST, initial=[...])
のようなものがあります。
フォームの最大数を制限する
max_num
パラメーターを formset_factory()に設定すると、フォームセットに表示されるフォームの数を制限できます。
max_num
の値が初期データの既存のアイテムの数よりも大きい場合、フォームの総数が追加される限り、最大extra
の追加の空白のフォームがフォームセットに追加されます。 max_num
を超えないようにしてください。 たとえば、extra=2
とmax_num=2
で、フォームセットが1つのinitial
アイテムで初期化されている場合、最初のアイテムのフォームと1つの空白のフォームが表示されます。
初期データの項目数がmax_num
を超えると、max_num
の値に関係なく、すべての初期データフォームが表示され、追加のフォームは表示されません。 たとえば、extra=3
とmax_num=1
で、フォームセットが2つの初期アイテムで初期化されている場合、初期データを含む2つのフォームが表示されます。
max_num
の値None
(デフォルト)では、表示されるフォームの数に上限があります(1000)。 実際には、これは制限なしと同等です。
デフォルトでは、max_num
は表示されるフォームの数にのみ影響し、検証には影響しません。 validate_max=True
が formset_factory()に渡されると、max_num
が検証に影響します。 validate_max を参照してください。
フォームセットの検証
フォームセットを使用した検証は、通常のForm
とほぼ同じです。 フォームセットにはis_valid
メソッドがあり、フォームセット内のすべてのフォームを検証する便利な方法を提供します。
フォームセットにデータを渡さなかったため、有効なフォームになりました。 フォームセットは、変更されていない余分なフォームを無視するのに十分スマートです。 無効な記事を提供した場合:
ご覧のとおり、formset.errors
は、フォームセット内のフォームに対応するエントリを持つリストです。 2つのフォームのそれぞれに対して検証が実行され、2番目の項目に予期されるエラーメッセージが表示されます。
通常のForm
を使用する場合と同様に、フォームセットのフォームの各フィールドには、ブラウザの検証用にmaxlength
などのHTML属性を含めることができます。 ただし、フォームセットのフォームフィールドにはrequired
属性が含まれません。これは、フォームを追加および削除するときに検証が正しくない可能性があるためです。
- BaseFormSet.total_error_count()
フォームセットに含まれるエラーの数を確認するには、total_error_count
メソッドを使用できます。
フォームデータが初期データと異なるかどうかを確認することもできます(つまり、 フォームはデータなしで送信されました):
ManagementFormを理解する
上記のフォームセットのデータに必要な追加データ(form-TOTAL_FORMS
、form-INITIAL_FORMS
、form-MAX_NUM_FORMS
)にお気づきかもしれません。 このデータはManagementForm
に必要です。 このフォームは、フォームセットに含まれるフォームのコレクションを管理するためにフォームセットによって使用されます。 この管理データを提供しない場合、例外が発生します。
表示されているフォームインスタンスの数を追跡するために使用されます。 JavaScriptを介して新しいフォームを追加する場合は、このフォームのカウントフィールドもインクリメントする必要があります。 一方、JavaScriptを使用して既存のオブジェクトの削除を許可している場合は、POST
データにform-#-DELETE
を含めて、削除するオブジェクトが適切に削除対象としてマークされていることを確認する必要があります。 POST
データには、関係なくすべてのフォームが存在することが予想されます。
管理フォームは、フォームセット自体の属性として使用できます。 テンプレートでフォームセットをレンダリングする場合、テンプレート:My formset.management form
をレンダリングすることですべての管理データを含めることができます(フォームセットの名前を適宜置き換えます)。
total_form_countおよびinitial_form_count
BaseFormSet
には、ManagementForm
、total_form_count
、およびinitial_form_count
に密接に関連するいくつかのメソッドがあります。
total_form_count
は、このフォームセット内のフォームの総数を返します。 initial_form_count
は、事前に入力されたフォームセット内のフォームの数を返します。また、必要なフォームの数を決定するためにも使用されます。 これらのメソッドのいずれかをオーバーライドする必要はおそらくないので、オーバーライドする前に、それらが何をするのかを必ず理解してください。
empty_form
BaseFormSet
は、JavaScriptを使用した動的フォームで簡単に使用できるように、プレフィックスが__prefix__
のフォームインスタンスを返す追加の属性empty_form
を提供します。
カスタムフォームセットの検証
フォームセットには、Form
クラスのメソッドと同様のclean
メソッドがあります。 ここで、フォームセットレベルで機能する独自の検証を定義します。
フォームセットclean
メソッドは、すべてのForm.clean
メソッドが呼び出された後に呼び出されます。 エラーは、フォームセットでnon_form_errors()
メソッドを使用して検出されます。
フォームセット内のフォームの数を検証する
Djangoは、送信されたフォームの最小数または最大数を検証するためのいくつかの方法を提供します。 フォーム数のよりカスタマイズ可能な検証が必要なアプリケーションでは、カスタムフォームセット検証を使用する必要があります。
validate_max
validate_max=True
が formset_factory()に渡された場合、検証では、データセット内のフォームの数から削除のマークが付けられたものを差し引いた数が [以下であることも確認されます。 X185X]。
validate_max=True
は、提供された初期データの量が多すぎたためにmax_num
を超えた場合でも、max_num
に対して厳密に検証します。
ノート
validate_max
に関係なく、データセット内のフォームの数がmax_num
を1000を超えて超えると、フォームはvalidate_max
が設定されているかのように検証できず、さらにmax_num
より上の最初の1000フォームのみが検証されます。 残りは完全に切り捨てられます。 これは、偽造されたPOST要求を使用したメモリ枯渇攻撃から保護するためです。
validate_min
validate_min=True
が formset_factory()に渡された場合、検証では、データセット内のフォームの数から削除のマークが付けられたものを差し引いた数が [以上であることも確認されます。 X188X]。
フォームの注文と削除の処理
formset_factory()は、フォームセット内のフォームの順序付けとフォームセットからのフォームの削除に役立つ2つのオプションのパラメーターcan_order
とcan_delete
を提供します。
can_order
- BaseFormSet.can_order
デフォルト:False
注文できるフォームセットを作成できます。
これにより、各フォームにフィールドが追加されます。 この新しいフィールドはORDER
という名前で、forms.IntegerField
です。 初期データから取得したフォームには、自動的に数値が割り当てられました。 ユーザーがこれらの値を変更するとどうなるかを見てみましょう。
can_delete
- BaseFormSet.can_delete
デフォルト:False
削除するフォームを選択する機能を備えたフォームセットを作成できます。
can_order
と同様に、これはDELETE
という名前の各フォームに新しいフィールドを追加し、forms.BooleanField
です。 削除フィールドのいずれかにマークを付けることでデータが取得されたら、deleted_forms
でそれらにアクセスできます。
ModelFormSet を使用している場合、formset.save()
を呼び出すと、削除されたフォームのモデルインスタンスが削除されます。
formset.save(commit=False)
を呼び出しても、オブジェクトは自動的に削除されません。 実際に削除するには、各 formset.deleted_objects でdelete()
を呼び出す必要があります。
一方、プレーンなFormSet
を使用している場合は、フォームセットのsave()
メソッドでformset.deleted_forms
を処理するのはあなた次第です。フォームを削除することを意味します。
フォームセットへのフィールドの追加
フォームセットにフィールドを追加する必要がある場合、これは簡単に実行できます。 フォームセットの基本クラスは、add_fields
メソッドを提供します。 このメソッドをオーバーライドするだけで、独自のフィールドを追加したり、順序フィールドと削除フィールドのデフォルトのフィールド/属性を再定義したりすることができます。
フォームセットフォームへのカスタムパラメータの受け渡し
フォームクラスがMyArticleForm
などのカスタムパラメータを受け取る場合があります。 フォームセットをインスタンス化するときに、次のパラメータを渡すことができます。
form_kwargs
は、特定のフォームインスタンスにも依存する場合があります。 フォームセットの基本クラスは、get_form_kwargs
メソッドを提供します。 このメソッドは、単一の引数(フォームセット内のフォームのインデックス)を取ります。 empty_form のインデックスはNone
です。
フォームセットのプレフィックスのカスタマイズ
レンダリングされたHTMLでは、フォームセットの各フィールドの名前にプレフィックスが含まれています。 デフォルトでは、プレフィックスは'form'
ですが、フォームセットのprefix
引数を使用してカスタマイズできます。
たとえば、デフォルトの場合、次のように表示されます。
しかし、ArticleFormset(prefix='article')
を使用すると、次のようになります。
これは、ビューで複数のフォームセットを使用する場合に役立ちます。
ビューとテンプレートでフォームセットを使用する
ビュー内でフォームセットを使用するのは、通常のForm
クラスを使用するのと同じくらい簡単です。 注意したいのは、テンプレート内の管理フォームを使用することだけです。 サンプルビューを見てみましょう。
manage_articles.html
テンプレートは次のようになります。
ただし、フォームセット自体に管理フォームを処理させることにより、上記のわずかなショートカットがあります。
上記は、フォームセットクラスのas_table
メソッドを呼び出すことになります。
手動でレンダリングされたcan_deleteおよびcan_order
テンプレートのフィールドを手動でレンダリングする場合は、テンプレート:Form.DELETE
を使用してcan_delete
パラメーターをレンダリングできます。
同様に、フォームセットに注文機能(can_order=True
)がある場合は、テンプレート:Form.ORDER
でレンダリングできます。
ビューで複数のフォームセットを使用する
必要に応じて、ビューで複数のフォームセットを使用できます。 フォームセットは、その動作の多くをフォームから借用します。 そうは言っても、prefix
を使用して、フォームセットのフォームフィールド名に特定の値のプレフィックスを付け、名前が衝突することなく複数のフォームセットをビューに送信できるようにすることができます。 これがどのように達成されるかを見てみましょう。
次に、フォームセットを通常どおりにレンダリングします。 正しくレンダリングおよび処理されるように、POSTケースと非POSTケースの両方でprefix
を渡す必要があることを指摘することが重要です。
各フォームセットのプレフィックスは、各フィールドのname
およびid
HTML属性に追加されるデフォルトのform
プレフィックスを置き換えます。