読者です 読者をやめる 読者になる 読者になる

AWS / PHP / Python ちょいメモ

amazon web service , PHP, Python を使ったときのメモ。日本語でググってもわからなかった事を中心に。

forms.Model と forms.ModelForm の 違いって

Django でアプリ作ってて、ふと気になったのでまとめてみた。ざっくり、こんな感じ?

機能 Model & Form ModelForm
validation 指示 Model & Form の両方で定義 Model で定義
フォーム上の項目 Form で定義 Model の定義から、ModelForm が自動決定 *対応表
フォームで表示する項目 Form で定義 ModelForm で定義
save メソッド Model.save() ModelForm.save() (Model.save() も使える)


DB の カラム以上のフィールドが不要なフォームでは、ModelForm を使うと断然コードが短く、簡潔になりますね。

ModelForm 利用時には、ModelForm の サブクラスに Meta クラスを作り、中に元になるModel (model = )や表示する項目 (fields =) に持たせることになります。Metaだけ持てば最低限OKになるので、Formの定義が超簡単!

また views.py の中でも、ModelForm が提供するものをメインで書けるようになり見通しがよくなります。


そもそものキッカケは、ManyToMany の 多対多 リレーションをはったModelに対するFormを上手く作る方法を知りたかったのです。Model & Form で頑張ってみたものの、ManyToMany になってるフィールドを上手く扱えず、ModelForm を利用した形で落ち着きました。なにが原因だったかは、また時間ができたら勉強しよう。



参考にした情報

このあたりを読んで、上の表を作成しました。Django の ドキュメントは、実際に作って shell の動作を読めば、ユーザー操作が確認できるの点がいいですね。Python 始めた頃は、意味不明でしたが(苦笑)

ちなみに途中まで読んで、Django 1.4 の 日本語ドキュメント でも、ほとんど一緒ってことに気づいた。なんてこった!!

class ModelForm

もし、データーベース Driven アプリを構築しているのであれば、Django models と 緊密にマップされたフォームをもつチャンスです。例えば、 BlogComment モデル を持っていて、ユーザーが投稿するためのフォームを作りたいとします。このケースでは、すでにモデルでフィールドを定義しているので、そのフォームでフィールドタイプを定義するのは冗長になります。

このような理由で、Django は フォーム Class を Django model から作る helper クラスを提供しています。

A full example

from django.db import models
from django.forms import ModelForm

...

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 __str__(self): # __unicode__ on Python 2
return self.name

class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)

class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']

class BookForm(ModelForm):
class Meta:
model = Book
fields = ['name', 'authors']

これらの ModelForm のサブクラス のモデルは、大まかに次の Form のサブクラスと等価になる (唯一の違いは、 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())

The save() method

各 ModelForm は save() メソッドを持ちます。このメソッドは、フォームに関連付けられたデータから、データベースオブジェクトを作成して保存します。ModelForm の サブクラスは、既存 Model インスタンスも キーワード引数 instance として受付可能です : 指定される場合 save() は インスタンスを更新しますし、指定されない場合 save() は新しく Model のインスタンスを作成します。

...

Django 1.4 の 日本語ドキュメント でも、ほとんど一緒ってことに気づいたので、意訳終わり。日本語ドキュメント読みます。

参考