単一のフォームについて複数回入力するなら FormSet 、
複数種類のフォームを画面遷移なしで入力するなら FormWizard がある。
FormWizard で FormSet を使ってみた
FormSet について
modelform_factory 、 modelformset_factory で Form と FormSet(ModelFormSet) を作った。
modelformset_factory については以下を参照。
- Django modelformset_factory便利 - Ian Lewis
- FormSet を空の状態で提供する (オブジェクト作成用のビューで使える) - Make組ブログ(移行して http://blog.hirokiky.org/ にあるよ)
下記のようなモデルを元に作成
class Production(models.Model): title = models.CharField("アニメタイトル", max_length=255) def __unicode__(self): return self.title class Character(models.Model): production = models.ForeignKey(Production, db_index=True) name = models.CharField("キャラ名", max_length=255) age = models.PositiveIntegerField("年齢") def __unicode__(self): return self.name
想定する画面は、
- あるアニメ作品に対する情報
- そのアニメに登場するキャラクターの情報を複数
を 1 画面 (画面遷移なし) で入力できるというもの。なので、
- Production を ProductionForm
- Character を CharacterFormSet
にした。これを FormWizard で扱う。
(Character は Production に対してリレーションを持ってるので、 View 内でうまくやる必要がある)
FormWizard について
基本的にはドキュメント読みましょう
- https://docs.djangoproject.com/en/dev/ref/contrib/formtools/form-wizard/
- フォームウィザード (Form wizard) — Django v1.0 documentation
主に上記 1.4 ドキュメントを読む。
今回扱うモデルはリレーションを持っているので Wizard でうまくやってやる
class AnimeWizard(SessionWizardView): def done(self, form_list, **kwargs): production = form_list[0].save() characters = form_list[1].save(commit=False) for c in characters: c.production = production c.save() return render_to_response('done.html', { 'form_data': [form.cleaned_data for form in form_list], })
(FormWizard.as_view([ProductionForm, CharacterFormSet]) で呼び出すことを想定している)
Wizard の入力が完了すると done() が呼び出されるので、そこでオブジェクトの保存をしてやる。
Character においては保存の前に、 Production へのリレーションを貼ってやる。
これでできる。
(ModelFormSet は 空の状態で提供する こと)