stack overflow で質問してた件が自己解決したのでQiitaに残して備忘録にしようと思い投稿しました.
初投稿なので温かい目で見てもらえればと思います.
#目的
ユーザーが指定した個数の入力フォームがほしい!
つまり動的にフィールドを追加してやりたかったわけです.
まあHTMLを直接追加してやれば出来るんですが,Djangoを使う以上でFormクラスでちゃんと管理してやりたいわけです.
ここに書いてある以外でもっといい書き方知ってたらコメントで教えてください.
#Formクラスの仕様
まずDjangoのFormクラスの仕様について自分の理解しているところをちょろっと書きます.
##フォームの基本的な使い方
from django import forms
class TestForm(forms.Form):
hoge = forms.CharField(label="hoge")
fuga = forms.CharField(label="fuga")
上のコードで作ったTestFormを作って,例えばform
とかいう名前でテンプレートに投げてやれば{{ form.as_p }}
とか{{ form.as_table }}
とかでinputフォームが出てくる.(この辺はDjangoの公式? Documentation のこことか別記事を参照.)
特にフォームをバラバラの位置に出したいときなど,個別にフォームを指定したいときは,{{ form.hoge }}
のように指定します.
##問題点:変数名=フィールド名
さて,今一度forms.py
のコードを見てもらうと,クラス直下で定義した変数名がそのままフィールド名になっていることが分かります. django.forms
を見てみるとどうもFormクラスはBaseFormというクラスを継承しているのですが,その際にメタクラスを使ったりして(この辺はよく理解していません)変数名をキー,定義したフィールドを値にしてfieldsという辞書型配列に格納しているようです.ですのでforms.py
で書いたクラスに配列で変数を定義したりしてもダメっぽいんですね.
#対策
配列を入れるとその配列の要素を名前とするフィールドをもつFormクラスを返してくれるような関数を作りました.
from django import forms
def create_form(myary, *arg):
f = forms.Form(*arg)
for val in myary:
f.fields[val] = forms.CharField(label=val)
return f
こんな感じで行けました!
views
はこんな感じ
class FormView(TemplateView):
def __init__(self):
self.keys = range(5)
self.params = {
'form':test(self.keys),
}
def get(self, request):
return render(request, 'temlate.html', self.params)
def post(self, request):
self.params['form'] = test(self.keys, request.POST)
return render(request, 'template.html', self.params)
ここではrange(5)
を渡してやってます.POSTのときにはrequest.POSTを一緒に投げてやる.
#改善点
引数のとこなんかは辞書型にしてやったり,labelとかバリデーションなんかの設定も投げれる様にすればよさげ
書いてて気づいたんですけど,たしかJSONでFormクラス作れたような...