Make組ブログ

Python、Webアプリや製品・サービス開発についてhirokikyが書きます。

Django の FormWizard で FormSet を使う

単一のフォームについて複数回入力するなら FormSet 、
複数種類のフォームを画面遷移なしで入力するなら FormWizard がある。

FormWizard で FormSet を使ってみた

環境

FormSet について

modelform_factory 、 modelformset_factory で Form と FormSet(ModelFormSet) を作った。
modelformset_factory については以下を参照。

下記のようなモデルを元に作成

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 について

基本的にはドキュメント読みましょう

主に上記 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 は 空の状態で提供する こと)

画面

まず作品名を入力

submit 押下後
次 (画面遷移は起こっていない) でキャラクター入力

( ゚Д゚ノノ"☆パチパチパチパチ