はじめに
ModelFormSetに初期値を設定する方法を説明します。
ModelFormは1つのテンプレートに1つしか作成することができません。
複数のModelFormを同時に作成する場合は、ModelFormSetを使用します。
概要
ModelFormSetに初期値を設定する方法は様々ありますが
こちらでは、ModelFormSetのインスタンス化時に初期値を設定する方法を説明します。
ビューからフォームに値を渡す方法も説明しているため、動的に初期値を設定することも可能です。
それでは、さっそく実装していきましょう。
説明
モデル
以下のモデル、フォーム、ビューを例に説明します。
from django.db import models
class Memo(models.Model):
title = models.CharField('タイトル', max_length=20)
text = models.TextField('内容')
def __str__(self):
return self.title
ビュー
画面にModelFormSetを表示するために、contextにインスタンスを渡します。
from django.views.generic import TemplateView
from apps.memo.models import Memo
class MemoView(TemplateView):
model = Memo
template_name = "memo/template.html"
def get_context_data(self, *args, **kwargs, request)
context = super().get_context_data(self, *args, **kwargs, request)
context['formset'] = MemoFormSet()
return context
フォーム
BaseMemoFormSetのinit関数で、初期値を設定できます。
self.querysetに代入された値が初期値となります。
そのため、Noneを代入した場合は初期値なしということになります。
self.querysetの値を上書きしない場合は、modelformset_factoryの第一引数で指定したモデルのすべてのデータが初期値に設定されます。ご注意ください。
from django.forms import ModelForm, BaseModelFormSet, modelformset_factory
from apps.memo.models import Memo
class MemoForm(ModelForm):
class Meta:
model = Memo
fields = ('title', 'text')
class BaseMemoFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 初期値を設定する
self.queryset = None
MemoFormSet = modelformset_factory(Memo, Form=MemoForm, formset=BaseMemoFormSet)
初期値を設定する
①②の順番でModelFormSetに初期値を設定します。
①ビューからフォームに値を渡す
②フォームで値を受け取り、初期値を設定する
ログインユーザーに紐づくデータを初期値に持たせたい場合などに活用できます。
ビューからユーザーIDを渡して、フォームでユーザーIDに紐づくデータを初期値に設定する。
といったことが可能です。
ビュー
MemoFormSetインスタンス化時に、MemoViewからMemoFormSetに値を渡します。
from django.views.generic import TemplateView
from apps.memo.models import Memo
from apps.memo.forms import MemoFormSet
class MemoView(TemplateView):
model = Memo
template_name = "memo/template.html"
def get_context_data(self, *args, **kwargs, request)
context = super().get_context_data(self, *args, **kwargs, request)
# MemoFormSetに値を渡す(key:'title', value:'test')
context['formset'] = MemoFormSet('title'='test')
return context
フォーム
BaseMemoFormSetのinit関数内でMemoViewで渡された値を受け取ることができます。
以下のソースではMemoViewから渡された値を、初期値の取得の条件に使用しています。
from django.forms import ModelForm, BaseModelFormSet, modelformset_factory
from apps.memo.models import Memo
class MemoForm(ModelForm):
class Meta:
model = Memo
fields = ('title', 'text')
class BaseMemoFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
# MemoViewで渡した'test'を受け取る
title = kwargs.pop('title')
super().__init__(*args, **kwargs)
# 初期値を設定する
self.queryset = Memo.objects.filter(title__startswith=title)
MemoFormSet = modelformset_factory(Memo, Form=MemoForm, formset=BaseMemoFormSet)