================================ モデルからフォームを生成する ================================ :revision-up-to: 17812 (1.4) unfinished .. module:: django.forms.models :synopsis: ModelForm and ModelFormset. .. currentmodule:: django.forms ``ModelForm`` ============= .. class:: ModelForm データベース駆動のアプリケーションを構築しているのなら、 Django のモデルに 対応したフォームが必要な場合があるでしょう。例えば、 ``BlogComment`` モデル を作っていて、読者がコメントを入力できるようなフォームを作成したいような場 合です。こうしたケースでは、すでにモデルにフィールドを定義しているので、新 たにフォームクラス用にフィールドを定義するのは無駄な作業でしかありません。 この理由から、 Django はモデルからフォームクラスを生成するためのヘルパクラ スを提供しています。 以下に例を示します:: >>> from django.forms import ModelForm # フォームクラスを生成 >>> class ArticleForm(ModelForm): ... class Meta: ... model = Article # 記事を追加するためのフォームを作成 >>> form = ArticleForm() # 既存の記事を変更するためのフォームを作成 >>> article = Article.objects.get(pk=1) >>> form = ArticleForm(instance=article) フィールド型 ------------- モデルから生成されるフォームクラスは、モデルの各フィールドに対応したフォー ムフィールドを持ちます。モデルフィールドには、それぞれデフォルトのフォーム フィールド型が定義されています。例えば、モデルの ``CharField`` 型には、 ``CharField`` 型のフォームフィールドが対応しています。モデルの ``ManyToManyField`` には、 ``MultipleChoiceField`` が対応しています。以下に 対応の一覧表を示します: =============================== ======================================== モデルフィールド型 フォームフィールド型 =============================== ======================================== ``AutoField`` フォーム上では表現されていません ``BigIntegerField`` ``IntegerField`` 。 ``min_value`` が -9223372036854775808 、 ``max_value`` が 9223372036854775807 にセットされています。 ``BooleanField`` ``BooleanField`` ``CharField`` ``CharField`` 。 ``max_length`` にはモ デルフィールドの ``max_length`` 値が設 定されます。 ``CommaSeparatedIntegerField`` ``CharField`` ``DateField`` ``DateField`` ``DateTimeField`` ``DateTimeField`` ``DecimalField`` ``DecimalField`` ``EmailField`` ``EmailField`` ``FileField`` ``FileField`` ``FilePathField`` ``CharField`` ``FloatField`` ``FloatField`` ``ForeignKey`` ``ModelChoiceField`` (下記参照) ``ImageField`` ``ImageField`` ``IntegerField`` ``IntegerField`` ``IPAddressField`` ``IPAddressField`` ``GenericIPAddressField`` ``GenericIPAddressField`` ``ManyToManyField`` ``ModelMultipleChoiceField`` (下記参照) ``NullBooleanField`` ``CharField`` ``PhoneNumberField`` ``USPhoneNumberField`` (``django.contrib.localflavor.us``) ``PositiveIntegerField`` ``IntegerField`` ``PositiveSmallIntegerField`` ``IntegerField`` ``SlugField`` ``SlugField`` ``SmallIntegerField`` ``IntegerField`` ``TextField`` ``widget=Textarea`` の ``CharField`` ``TimeField`` ``TimeField`` ``URLField`` ``URLField`` 。 ``verify_exists`` には モデルフィールドの ``verify_exists`` 値が設定されます。 =============================== ======================================== .. versionadded:: 1.2 ``BigIntegerField`` は Django 1.2 で新たに定義されました。 お気付きかもしれませんが、 ``ForeignKey`` や ``ManyToManyField`` といったモ デルフィールドは特別扱いされています: * ``ForeignKey`` は ``django.forms.ModelChoiceField`` で表現されて います。 ``ModelChoiceField`` は、選択肢がモデルの ``QuerySet`` であ るような ``ChoiceField`` です。 * ``ManyToManyField`` は ``django.forms.ModelMultipleChoiceField`` で表現されています。 ``ModelMultipleChoiceField`` は、選択肢がモデル の ``QuerySet`` であるような ``MultipleChoiceField`` です。 さらに、生成されるフォームフィールドには、以下の属性が付加されます: * モデルフィールドに ``blank=True`` が設定されていると、フォームフィー ルドの ``required`` は ``False`` に設定されます。それ以外の場合には、 ``required=True`` です。 * フォームフィールドの ``label`` にはモデルフィールドの ``verbose_name`` の値を使います。このとき先頭の文字は大文字に変換され ます。 * フォームフィールドの ``help_text`` にはモデルフィールドの ``help_text`` の値を使います。 * モデルフィールドに ``choices`` が設定されている場合、フォームフィール ドの ``widget`` は ``Select`` に設定されます。また、選択肢にはモデル フィールドの ``choices`` の値を使います。通常、選択肢の中には、空の 選択肢が加えられ、フォームの表示時にデフォルトで選択されています。 フィールドが必須のフィールドである場合、ユーザは必ず空の選択肢以外か ら選択せねばなりません。モデルフィールドが ``blank=False`` で、かつ ``default`` 値が明に設定されている場合、空の選択肢は表示されません (``default`` の値が選択された状態で表示されます)。 あるモデルからフォームを作成する場合、モデルのフォームフィールドに対応する フォームフィールドをオーバライドできます。後述の `デフォルトのフィールド型をオーバライドする`_ を参照してください。 詳細な例 --------- 以下のような一連のモデルを考えましょう:: from django.db import models from django.forms import ModelForm TITLE_CHOICES = ( ('MR', 'Mr.'), ('MRS', 'Mrs.'), ('MS', 'Ms.'), ) class Author(models.Model): name = models.CharField(max_length=100) title = models.CharField(max_length=3, choices=TITLE_CHOICES) birth_date = models.DateField(blank=True, null=True) def __unicode__(self): return self.name class Book(models.Model): name = models.CharField(max_length=100) authors = models.ManyToManyField(Author) class AuthorForm(ModelForm): class Meta: model = Author class BookForm(ModelForm): class Meta: model = Book 上に挙げた例中の ``ModelForm`` サブクラスは、以下のフォームクラスとほぼ同じ になります (違いは ``save()`` メソッドの動作だけです。これについてはすぐ後 で説明します):: from django import forms class AuthorForm(forms.Form): name = forms.CharField(max_length=100) title = forms.CharField(max_length=3, widget=forms.Select(choices=TITLE_CHOICES)) birth_date = forms.DateField(required=False) class BookForm(forms.Form): name = forms.CharField(max_length=100) authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) ``is_valid()`` メソッドと ``errors`` ---------------------------------------- 最初に ``ModelForm`` の ``is_valid()`` を呼び出すか、 あるいは ``errors`` 属性にアクセスしたときに :ref:`モデルのバリデーション ` と同様にフォームバリデーション が行われます。 これには ``ModelForm`` コンストラクタに渡したモデルをクリーニングするという 副作用があります。例えば、あなたのフォームに対して ``is_valid()`` を呼ぶと 日付フィールドが実際の日付フィールドに変換されてしまいます。 .. _The save() method: ``save()`` メソッド --------------------- ``ModelForm`` から生成されたフォームは ``save()`` メソッドを備えています。 このメソッドは、フォームに結びつけられたデータから、モデルオブジェクトを生 成してデータベースに保存します。 ``ModelForm`` のサブクラスは既存のモデルイ ンスタンスをキーワード引数 ``instance`` にしてインスタンス化できます。 ``instance`` を指定してモデルフォームを生成すると、モデルフォームの ``save()`` はこのインスタンスを更新して保存します。 ``instance`` を指定しな ければ、 ``save()`` はモデルフォームで指定しているモデルの新たなインスタン スを生成します:: # POST データから新たなフォームインスタンスを生成 >>> f = ArticleForm(request.POST) # フォームデータから新たな Article オブジェクトを生成 >>> new_article = f.save() # 既存の Article オブジェクトからフォームを生成 >>> a = Article.objects.get(pk=1) >>> f = ArticleForm(instance=a) >>> f.save() # 既存の Article オブジェクトを編集するためのフォームを作成します。 # ただし、 POST データを使ってフォームに値を設定します。 >>> a = Article.objects.get(pk=1) >>> f = ArticleForm(request.POST, instance=a) >>> f.save() form.errors が True であると評価されると、 ``save()`` は ``ValueError`` を送出す るので注意してください。 ``save()`` メソッドはオプション ``commit`` キーワード引数を持っています。こ の引数には ``True`` または ``False`` を指定します。 ``save()`` を ``commit=False`` で呼び出すと、データベースに保存する前のモデルオブジェクト を返します。返されたオブジェクトに対して、最終的に ``save()`` を呼び出すか どうかは自由です。この機能は、オブジェクトを実際に保存する前に何らかの処理 を行いたい場合や、特殊なオプション付きで :ref:`モデルオブジェクトを保存したい ` 場合に便利 です。 ``commit`` はデフォルトでは ``True`` に設定されています。 モデルが他のモデルに対する多対多のリレーションを持っている場合、 ``commit=False`` を使うともう一つの副作用があります。多対多のリレーションを 持つモデルから生成したフォームを保存する際、 Django は多対多のリレーション に対するデータをすぐに保存できません。なぜなら、 ``save(commit=False)`` の 対象であるオブジェクトはまだデータベースに保存されていないため、オブジェク トに対する多対多の関係を保存するためのテーブルを更新できないからです。 .. To work around this problem, every time you save a form using ``commit=False``, Django adds a ``save_m2m()`` method to your ``ModelForm`` subclass. After you've manually saved the instance produced by the form, you can invoke ``save_m2m()`` to save the many-to-many form data. For example:: この問題を回避するために、Django は ``commit=False`` でフォームを保存した直 後に、 ``save_m2m()`` メソッドを ``ModelForm`` のサブクラスへ追加します。フォーム から生成したインスタンスを手動で保存した後で ``save_m2m()`` を呼び出せば、 多対多のフォームデータを保存できます。以下に例を示します:: # POST データから新たなフォームインスタンスを生成 >>> f = AuthorForm(request.POST) # インスタンスを生成、ただし保存はしない >>> new_author = f.save(commit=False) # new_author のフィールド値を変更 >>> new_author.some_field = 'some_value' # 新たなインスタンスを保存 >>> new_author.save() # 最後に、多対多のフォームデータを保存 >>> f.save_m2m() ``save_m2m()`` の呼び出しが必要なのは、 ``save(commit=False)`` を使った場合 だけです。単に ``save()`` を呼び出すだけなら、多対多のデータを含む全てのデー タが保存され、他に何らかのメソッドを呼び出す必要はありません。以下に例を示 します:: # POST データから新たなフォームインスタンスを生成 >>> a = Author() >>> f = AuthorForm(request.POST, instance=a) # 新たな Author インスタンスを生成して保存。他にはなにもしなくてよい >>> new_author = f.save() .. Other than the ``save()`` and ``save_m2m()`` methods, a ``ModelForm`` works exactly the same way as any other ``forms`` form. For example, the ``is_valid()`` method is used to check for validity, the ``is_multipart()`` method is used to determine whether a form requires multipart file upload (and hence whether ``request.FILES`` must be passed to the form), etc. See :ref:`binding-uploaded-files` for more information. ``save()`` および ``save_m2m()`` メソッド以外は、 ``ModelForm`` は他の ``forms`` で作られたフォームと全く同じように動作します。例えば、 データの検証は ``is_valid()`` で行えますし、 ``is_multipart()`` メソッドを使えばフォームがマルチパートのファイルアップロードを要求している かどうか (そして ``request.FILES`` をフォームに渡さなければならないかどうか) 判別できます。詳しくは、 :ref:`binding-uploaded-files` を参照してください。 モデルの一部のフィールドだけからフォームを生成する --------------------------------------------------- 場合によっては、フォームを生成するときに、モデルの一部のフィールドだけを表 示したいことでしょう。モデルフィールドの一部だけを使って ``ModelForm`` を作 るには、以下の 3 つの方法があります: 1. モデルフィールドに ``editable=False`` を定義します。その結果、 モデルフォームを使って生成したフォームは *全て* このフィールドを含ま なくなります。 2. ``ModelForm`` サブクラスで、内部クラス ``Meta`` の ``fields`` 属性を 設定します。この属性にはフィールド名からなるリストを設定します。設定 すると、指定されたフィールドだけを含むフォームを生成します。 fieldsに指定された名前の順番はフォームがレンダーされる時に尊重されます。 3. ``ModelForm`` サブクラスで、内部クラス ``Meta`` の ``exclude`` 属性を 設定します。この属性にはフィールド名からなるリストを設定します。設定 すると、指定されたフィールドを含まないフォームを生成します。 例えば、 (上で定義した) ``Author`` モデルから、 ``name`` と ``title`` フィールドだけを含むようなフォームを作成したければ、以下の ようにして ``fields`` または ``exclude`` を指定します:: class PartialAuthorForm(ModelForm): class Meta: model = Author fields = ('name', 'title') class PartialAuthorForm(ModelForm): class Meta: model = Author exclude = ('birth_date',) Author モデルには ``'name'``, ``'title'``, ``'birth_date'`` の 3 つ のフィールドしかないので、上のフォームは全く同じフォームフィールド を持ちます。 .. note:: ``ModelForm`` を使ってフォームを生成するときに ``fields`` や ``exclude`` を指定すると、生成されたフォームの ``save()`` を呼び出した ときに、フォームに含まれていないフィールドのデータは設定されません。 また、除外フィールドをフォームに手動で追加し直してもモデルインスタンス から初期化されることはありません。 このため、フォームに含まれていないフィールドに対応するモデルフィールド が、空の値を許さないように定義されていて、かつデフォルトの値が指定され ていない場合、モデルインスタンスが不完全なために Django がオブジェクト の保存を抑止し、 ``save()`` は失敗します。これを避けるには、フォームの インスタンスを生成するときに、不足しているフィールドでかつ必須のフィー ルドに対する初期値を指定してください:: author = Author(title='Mr') form = PartialAuthorForm(request.POST, instance=author) form.save() あるいは、 ``save(commit=False)`` を使って、必須のフィールドの値を手動 で設定してください:: form = PartialAuthorForm(request.POST) author = form.save(commit=False) author.title = 'Mr' author.save() ``save(commit=False)`` については、 `フォームを保存する`_ も参照してください。 .. _フォームを保存する: `save() メソッド`_ デフォルトのフィールド型をオーバライドする -------------------------------------------- .. versionadded:: 1.2 ``widgets`` 属性はDjango 1.2で新たに導入されました。 上の `フィールド型`_ で説明したデフォルトのフィールド型は、いわゆる気の利い たデフォルト値にすぎません。モデル上で ``DateField`` として定義されている フィールドは、フォーム上でも ``DateField`` として表現されてほしいというのが 普通でしょう。とはいえ、 ``ModelForm`` は、あるモデルフィールドのフォーム フィールド型を変更できるという柔軟性を備えています。 フィールドに対するカスタムウィジェットを指定するには、 ``Meta`` インナークラス の ``widgets`` 属性を使います。 これはフィールド名をウィジェットクラスあるいは インスタンスにマッピングさせるディクショナリです。 例えば、 ``Author`` の ``CharField`` の ``name`` 属性を、 デフォルトの ```` では無く ``