知識の枝

"All is well"

Django formsetの絞り込みと同時編集

約135日前 2021年7月14日21:26
デジタル
Django

改訂履歴


2021/7/14 投稿

1. 背景


Djangoを使った開発中に覚えたことを備忘録として残します。

今回はformsetで表示するフォームを限定する方法を解説します。


2. ゴール


とあるモデルの同時編集画面において、条件に合ったモデルだけ一覧表示する。


3. はじめに


みなさん「formset」というのはご存じでしょうか?

例えば文献管理アプリに新しい文書を登録する場合を考えましょう。

登録したい文書が5つあるとき、文書モデル"Document"を5回登録する必要があります。


繰返し登録したい場合は、

①「新規登録ボタン」を押して、「登録ページ」を開く。

②登録内容を入力し、「登録ボタン」を押す。

③データベースにDocumentモデルインスタンスを登録する。

①~③のループを登録したい文書の数だけ実行する必要があります。


でもこれって作業性が悪いですよね?

できれば「登録ページ」で同時に複数個のモデルを登録したいところです。

そんなときに使えるのが「formset」です。

「formset」を使うと同時に複数の入力フォームが表示されるので、登録したいモデルの数だけ情報を入力すれば、その数だけモデルを登録することができます!


また、この「formset」を使うと、「登録済みのモデルを複数表示して同時に内容編集」なんてこともできちゃいます。

ただ、何も考えずにモデルの同時編集を行うと、登録されている全てのDocumentモデルの編集フォームが表示されてしまいます。


例えば著者が ”芥川龍之介” の文書のみを編集したい場合、上記のように全てのモデルが表示されていては、対象の編集フォームを探すのが大変です。

著者="芥川龍之介" となっているモデルの編集フォームだけが表示してあったら探す手間が省けて便利ですよね?

今回解説するのは上記のような「同時編集」を行う際に、編集するモデルを絞り込んで一覧表示する方法を解説します。



4. formsetの絞り込み


文書を登録するフォームを下記のように作ったとします。
forms.py
class DocumentForm(forms.ModelForm):
"""文書 を追加するフォーム"""
class Meta:
model = Document
fields = (
'title',
'author',
'published',
)

このフォームをベースにフォームセットを作成します。
fomrs.py
class DocumentForm(forms.ModelForm):
"""文書 を追加するフォーム"""
class Meta:
model = Document
fields = (
'title',
'author',
'published',
)

EditDocumentFormSet = forms.modelformset_factory(Document,
form=DocumentForm,
extra=0)
既に登録済みのモデルを編集するフォームセットなので「extra=0」として、空のフォームが表示されないようにしています。


続いてviews.pyの中身です。

「formset」で絞り込みを行う前に "ある準備" が必要です。

それは、「絞り込み済みのQuerySetを取得すること」です。


今回は「著者が ”芥川龍之介” の文書のみを編集したい」という例でしたので、目的のQuerySetを取得しましょう。
views.py
selected_document = Document.objects.filter(author="芥川龍之介")
これで事前準備は完了です。

続いてhtmlテンプレートに渡すフォームセットを定義します。
views.py
edit_formset = EditDocumentFormSet(request.POST or None, queryset=selected_document)
forms.pyで作成したフォームセットのqueryset引数に上記で準備しておいたselected_documentを指定します。

あとはedit_formsetをhtmlに渡してフォームを表示させるだけです。
views.py
context = {
'edit_formset': edit_formset,
}

return render(request, template, context)


html上ではこのように書いてフォームを表示させます。
html
<form method="post">
{% for form in edit_formset %}
{{form.as_p}}
{% endfor %}
{{ edit_formset.management_form }}
{% csrf_token %}
<button type="submit">送信</button>
</form>
views.pyから受け取った「edit_formset」をfor文で取り出し、フォームを表示させます。

{% csrf_token %} はPOSTを扱うときには必須のおまじないです。

また、formsetを使う場合は {{ edit_formset.management_form }} もおまじないとして書きます。

どちらも忘れず書いておきましょう。


ここまで順調に進められていれば、以下のように「登録済みのモデルを複数表示して同時に内容編集」ができるようになっているはずです。





5. さいごに


フォームセットの便利な使い方を1つ覚えられましたね。

ぜひ自分の手で実際に書いてみて動作を確認してみてください!