# Django 5.0.9.dev20240806133106 ドキュメント

# モデルからフォームを作成する

## `ModelForm`

class `ModelForm`

データベース中心のアプリケーションを作成している場合、Django モデルに密接にマップするフォームを使うことになるでしょう。例えば、`BlogComment` モデルを持っていて、閲覧者がコメントを送信できるフォームを作成したくなったとしましょう。この場合、すでにモデル内にフィールドが定義されているので、フォーム内にフィールドタイプを改めて定義するのは冗長でしょう。

このためDjango には、Django モデルから `Form` クラスを生成できるようなヘルパークラスを用意してあります。

例えば次のようにします:

    >>> from django.forms import ModelForm
    >>> from myapp.models import Article

    # Create the form class.
    >>> class ArticleForm(ModelForm):
    ...     class Meta:
    ...         model = Article
    ...         fields = ["pub_date", "headline", "content", "reporter"]
    ...

    # Creating a form to add an article.
    >>> form = ArticleForm()

    # Creating a form to change an existing article.
    >>> article = Article.objects.get(pk=1)
    >>> form = ArticleForm(instance=article)

### フィールドの型

生成された `Form` クラスは、指定された全てのモデルフィールドに対して、`fields` 属性で指定された順番でフォームフィールドを有します。

各モデルフィールドは、対応するデフォルトのフォームフィールドを持ちます。例えば、モデル上の `CharField` はフォーム上で `CharField` として表現されます。モデル `ManyToManyField` は `MultipleChoiceField` として表現されます。 以下は、各フィールドの対応表です:

モデルフィールド | フォームフィールド
--- | ---
`AutoField` | フォーム上では表示されません。
`BigAutoField` | フォーム上では表示されません。
`BigIntegerField` | `IntegerField` で `min_value` が -9223372036854775808 から `max_value` に 9223372036854775807 セットされます。
`BinaryField` | `editable` がモデルフィールド上で `True` にセットされていた場合、`CharField` です。それ以外の場合フォーム内で描画されません。
`BooleanField` | `BooleanField` です。`null=True` の場合は `NullBooleanField` です。
`CharField` | `CharField` で、`max_length` はモデルフィールドの `max_length` にセットされます。また `null=True` の場合 `empty_value` が `None` にセットされます。
`DateField` | `DateField`
`DateTimeField` | `DateTimeField`
`DecimalField` | `DecimalField`
`DurationField` | `DurationField`
`EmailField` | `EmailField`
`FileField` | `FileField`
`FilePathField` | `FilePathField`
`FloatField` | `FloatField`
`ForeignKey` | `ModelChoiceField` (see below)
`ImageField` | `ImageField`
`IntegerField` | `IntegerField`
`IPAddressField` | `IPAddressField`
`GenericIPAddressField` | `GenericIPAddressField`
`JSONField` | `JSONField`
`ManyToManyField` | `ModelMultipleChoiceField` (以下を参照)
`PositiveBigIntegerField` | `IntegerField`
`PositiveIntegerField` | `IntegerField`
`PositiveSmallIntegerField` | `IntegerField`
`SlugField` | `SlugField`
`SmallAutoField` | フォーム上では表示されません。
`SmallIntegerField` | `IntegerField`
`TextField` | `CharField` で `widget=forms.Textarea` です。
`TimeField` | `TimeField`
`URLField` | `URLField`
`UUIDField` | `UUIDField`

お気付きかもしれませんが、 `ForeignKey` と `ManyToManyField` の 2 つのモデルフィールドは特殊なケースとなります:

- `ForeignKey` は `django.forms.ModelChoiceField` によって表現され、モデルの `QuerySet` を選択肢として持つ `ChoiceField` です。
- `ManyToManyField` は `django.forms.ModelMultipleChoiceField` によって表現され、モデルの `QuerySet` を選択肢として持つ `MultipleChoiceField` です。

加えて、生成されたフォームフィールドはそれぞれ以下の通り属性がセットされます:

- モデルフィールドに `blank=True` が設定されている場合、フォームフィールド上で `required` が `False` にセットされます。それ以外の場合は `required=True` となります。
- フォームフィールドの `label` はモデルフィールドの `verbose_name` の最初の文字を大文字にしたものがセットされます。
- フォームフィールドの `help_text` はモデルフィールドの `help_text` がセットされます。
- モデルフィールドに `choices` が設定されている場合、フォームフィールドの `widget` は `Select` にセットされ、選択肢にはモデルフィールドの `choices` が使われます。通常、選択肢には空欄の選択肢が追加され、デフォルトで選択されることになります。フィールドが required の場合、ユーザは選択肢を選ぶ必要があります。モデルフィールドに `blank=False` および明示的な `default` 値が設定されている場合、空欄の選択肢は表示されません (代わりに `default` 値が選択された状態で表示されます) 。

与えられたモデルフィールドに対して使われるフォームフィールドをオーバーライドすることもできます。後述の Overriding the default fields を参照してください。

### 完全な具体例

以下のような一連のモデルを考えていきましょう:

    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 __str__(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
            fields = ["name", "title", "birth_date"]

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

これらのモデルでは、上記の `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())

### `ModelForm` の検証 (バリデーション)

`ModelForm` のバリデーションには、以下の 2 つのステップが存在します:

1. フォームのバリデーションを実施する
2. モデルのインスタンスのバリデーションを実施する

通常のフォームのバリデーションと同じように、モデルフォームのバリデーションは `is_valid()` が呼ばれたときや `errors` 属性にアクセスしたとき、暗黙的に実行されます。また、実際にはあまり使うメソッドではありませんが、明示的に `full_clean()` を呼んだときにもバリデーションが実行されます。

`Model` バリデーション (`Model.full_clean()`) は、フォームバリデーションのステップ内でフォームの `clean()` メソッドが呼ばれたすぐ直後に実行されます。

警告

クリーニングのプロセスは、様々な方法で `ModelForm` コンストラクタに渡されたモデルのインスタンスを修正します。例えば、モデル上のあらゆる日付フィールドは、実際の date オブジェクトに変換されます。失敗したバリデーションは、一貫性のない状態でモデルインスタンスを元のままにしておくため、これを再利用するのはお勧めできません。

#### `clean()` メソッドをオーバーライドする

通常のフォームと同じ方法でモデルフォーム上の `clean()` メソッドをオーバーライドして、バリデーションの動作を追加できます。

モデルのオブジェクトに付属したモデルフォームのインスタンスは、`instance` 属性を持ち、メソッドが特定のモデルのインスタンスにアクセスできるようにします。

警告

`ModelForm.clean()` メソッドは、モデルバリデーション に、`unique`、`unique_together` または `unique_for_date|month|year` としてマークされたモデルフィールドの一意性を検証させます。

`clean()` メソッドをオーバーライドして、なおかつこのバリデーションを維持したい場合、親クラスの `clean()` メソッドを呼ぶ必要があります。

#### モデルバリデーションとのやり取り

バリデーションプロセスの一部として、`ModelForm` フォーム上で対応するフィールドを持つモデルのそれぞれのフィールドの `clean()` メソッドを呼び出します。モデルフィールドを除外した場合、これらのフィールドに対してはバリデーションが実行されません。フィールドのクリーニングとバリデーションの詳しい働き方については、フォームバリデーション ドキュメントを参照してください。

モデルの `clean()` メソッドは一意性のチェックがされる前に呼び出されます。モデルの `clean()` フックのより詳しい情報については、オブジェクトのバリデーションを行う を参照してください。

#### モデルの `error_messages` のレンダリングを考える

`フォームフィールド` や フォーム Meta のレベルで定義されたエラーメッセージは、常に `モデルフィールド` のレベルで定義されたエラーメッセージより優先されます。

`モデルフィールド` で定義されたエラーメッセージは、モデルバリデーション のステップの間に `ValidationError` が発生したときに、対応するエラーメッセージがフォームのレベルで定義されていない場合にのみ使用されます。

`NON_FIELD_ERRORS` キーを `Meta` クラス内の `error_messages` ディクショナリに追加することで、モデルバリデーションによって発生する `NON_FIELD_ERRORS` に対するエラーメッセージをオーバーライドできます。

    from django.core.exceptions import NON_FIELD_ERRORS
    from django.forms import ModelForm

    class ArticleForm(ModelForm):
        class Meta:
            error_messages = {
                NON_FIELD_ERRORS: {
                    "unique_together": "%(model_name)s's %(field_labels)s are not unique.",
                }
            }

### `save()` メソッド

全ての `ModelForm` は `save()` メソッドも持っています。このメソッドは、フォームに結びつけられたデータからデータベースオブジェクトを生成して保存します。`ModelForm` のサブクラスはキーワード引数 `instance` として既存のモデルインスタンスを受け取ることができます; これが指定されると、`save()` はそのインスタンスを更新するようになります。 指定されない場合は、`save()` は指定されたモデルの新しいインスタンスを生成します:

    >>> from myapp.models import Article
    >>> from myapp.forms import ArticleForm

    # Create a form instance from POST data.
    >>> f = ArticleForm(request.POST)

    # Save a new Article object from the form's data.
    >>> new_article = f.save()

    # Create a form to edit an existing Article, but use
    # POST data to populate the form.
    >>> a = Article.objects.get(pk=1)
    >>> f = ArticleForm(request.POST, instance=a)
    >>> f.save()

フォームが バリデーションされていない 場合、`save()` を呼び出すと、`form.errors` をチェックすることでこれを行います。フォーム内のデータが適正ではない場合は `ValueError` が発生します -- 例えば、`form.errors` が `True` だと評価された場合です。

オプションのフィールドがフォームのデータに表示されない場合、結果のモデルインスタンスはモデルフィールドの `default` を使用します。この動作は、 `CheckboxInput`, `CheckboxSelectMultiple`, または `SelectMultiple` (または `value_omitted_from_data()` メソッドが常に `False` を返すカスタムウィジェット) を使用するフィールドには適用されません。チェックされていないチェックボックスと、選択されていない `<select multiple>` は HTML フォーム送信のデータには表示されないからです。 API を設計していて、これらのウィジェットを使用するフィールドのデフォルトのフォールバック動作が必要な場合は、カスタムフォームフィールドまたはウィジェットを使用します。

この `save()` には、省略可能な `commit` キーワード引数があり、`True` ないし `False` を取ります。`save()` を `commit=False` で呼び出した場合、データベースにまだ保存されていないオブジェクトを返します。この場合、結果のモデルインスタンスで `save()` を呼び出すかどうかはあなた次第です。これは、保存前にオブジェクトで独自のプロセスを実行したい場合、もしくは特別な モデル保存オプション を使いたい場合に有用です。 `commit` はデフォルトでは `True` です。

`commit=False` を使う際のもう 1 つの副作用は、モデルに他のモデルとの多対多の関係がある場合に見られます。フォームを save するときにモデルに多対多の関係があり `commit=False` を指定した場合、Django は多対多の関係に対してフォームのデータを即座に保存することができません。これは、インスタンスがデータベース上に存在するようになるまで、インスタンスに対して多対多のデータを保存することが不可能だからです。

この問題を扱うために、`commit=False` を使ったフォームを save するたびに、Django は `save_m2m()` メソッドをあなたの `ModelForm` サブクラスに追加します。フォームによって生成されたインスタンスを手動で save した後に、多対多のフォームデータを保存するには `save_m2m()` を実行します。例えば:

    # Create a form instance with POST data.
    >>> f = AuthorForm(request.POST)

    # Create, but don't save the new author instance.
    >>> new_author = f.save(commit=False)

    # Modify the author in some way.
    >>> new_author.some_field = "some_value"

    # Save the new instance.
    >>> new_author.save()

    # Now, save the many-to-many data for the form.
    >>> f.save_m2m()

`save_m2m()` を呼び出す必要があるのは `save(commit=False)` を使ったときだけです。フォーム上で `save()` を使用すると、多対多のデータを含むすべてのデータが保存されます。 たとえば:

    # Create a form instance with POST data.
    >>> a = Author()
    >>> f = AuthorForm(request.POST, instance=a)

    # Create and save the new author instance. There's no need to do anything else.
    >>> new_author = f.save()

`save()` と `save_m2m()` メソッドのほかは、`ModelForm` は `forms` のフォームとまったく同じ方法で動作します。例えば、`is_valid()` メソッドは妥当性をチェックするために使用される、`is_multipart()` メソッドはフォームがマルチパートのファイルアップロードを必要とするかどうかを (ゆえに `request.FILES` がフォームに渡される必要があるかどうかも) 決める、などです。詳しくは アップロードされたファイルをフォームにバインドする を参照してください。

### 使うフィールドを選択する

`fields` 属性を使って、フォームで編集すべき全てのフィールドを明示的に指定することを強くお勧めします。そうしないと、フォームで予期せず特定のフィールドを設定できるようになり、セキュリティ上の問題が発生しやすくなります。特に新しいフィールドがモデルに追加されたときに起こりがちです。フォームのレンダリング方法によっては、Webページで問題が目に見えないことさえあります。

別のアプローチとしては、すべてのフィールドを自動的に含めるか、一部のフィールドだけを削除する方法があります。この基本的なアプローチは安全性がかなり低いことが知られており、主要なウェブサイトで深刻な悪用が行われています (GitHub など)。

しかし、これらのセキュリティ上の懸念があなたに当てはまらないと保証できる場合には、2 つのショートカットが利用可能です:

1. `fields` 属性に、特殊な値 `'__all__'` をセットして、モデル内の全てのフィールドが使われるように指定します。例えば:

       from django.forms import ModelForm

       class AuthorForm(ModelForm):
           class Meta:
               model = Author
               fields = "__all__"

2. `ModelForm` の中の `Meta` クラスの `exclude` 属性に、フォームから除外されるフィールドのリストをセットします。

   例:

       class PartialAuthorForm(ModelForm):
           class Meta:
               model = Author
               exclude = ["title"]

   `Author` モデルは 3 つのフィールド `name`、`title`、`birth_date` を持っているため、これで `name` と `birth_date` がフォームに表示されることになります。

このどちらかが使われた場合、フォーム内で表示されるフィールドの順番はモデル内でフィールドが定義された順番となり、`ManyToManyField` インスタンスは最後に表示されます。

加えて、Django は以下のルールも適用します: モデルフィールドで `editable=False` をセットした場合、`ModelForm` を通じて生成された 全ての フォームはそのフィールドを含みません。

注釈

上記のロジックでフォームに含まれない全てのフィールドは、フォームの `save()` メソッドでセットされません。また、除外したフィールドを手動でフォームに追加し直した場合、モデルインスタンスから初期化されることはありません。

Django は不完全なモデルを保存しないようにするため、モデルの設定でフィールドを空にすることを許容しておらず、かつ除外されたフィールドに対するデフォルト値を指定しなかった場合、除外されたフィールドを含む `ModelForm` を `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)` の使用について、詳しくは section on saving forms を参照してください。

### デフォルトのフィールドをオーバライドする

前述の Field types テーブルで説明したとおり、デフォルトのフィールドタイプは実用的なデフォルトです。モデルに `DateField` がある場合、フォーム内で `DateField` として表示したいことでしょう。しかし、`ModelForm` では、与えられたモデルに足してフォームフィールドを変更する柔軟性があります。

フィールドに対して独自のウィジェットを指定するには、内部の `Meta` クラスの `widgets` を使用してください。これは、フィールド名としジェットのクラスやインスタンスをマッピングするディクショナリです。

例えば、`Authoer` の `name` 属性に対する `CharField` を、デフォルトの `<input type="text">` の代わりに `<textarea>` で表示したい場合、フィールドのウィジェットをオーバーライドします:

    from django.forms import ModelForm, Textarea
    from myapp.models import Author

    class AuthorForm(ModelForm):
        class Meta:
            model = Author
            fields = ["name", "title", "birth_date"]
            widgets = {
                "name": Textarea(attrs={"cols": 80, "rows": 20}),
            }

`widgets` 辞書はウィジェットのインスタンス（例: `Textarea(...)` ）またはクラス（例: `Textarea`）を受け付けます。空でない `choices` 属性を持つモデルフィールドでは `widgets` 辞書は無視されることに注意してください。この場合、フォームフィールドをオーバーライドして別のウィジェットを使用する必要があります。

同様に、フィールドをさらにカスタマイズしたい場合、内部の `Meta` クラスの `labels`、`help_texts`、`error_messages` と言った属性を指定できます。

例えば、`name` フィールドに対する文字列に直面する全てのユーザの文章をカスタマイズしたい場合:

    from django.utils.translation import gettext_lazy as _

    class AuthorForm(ModelForm):
        class Meta:
            model = Author
            fields = ["name", "title", "birth_date"]
            labels = {
                "name": _("Writer"),
            }
            help_texts = {
                "name": _("Some useful help text."),
            }
            error_messages = {
                "name": {
                    "max_length": _("This writer's name is too long."),
                },
            }

また、 `field_classes` や `formfield_callback` を指定して、フォームがインスタンス化するフィールドのタイプをカスタマイズすることもできます。

例えば、`slug` フィールドに対して `MySlugFormField` を使いたい場合、以下のようにできます:

    from django.forms import ModelForm
    from myapp.models import Article

    class ArticleForm(ModelForm):
        class Meta:
            model = Article
            fields = ["pub_date", "headline", "content", "reporter", "slug"]
            field_classes = {
                "slug": MySlugFormField,
            }

もしくは:

    from django.forms import ModelForm
    from myapp.models import Article

    def formfield_for_dbfield(db_field, **kwargs):
        if db_field.name == "slug":
            return MySlugFormField()
        return db_field.formfield(**kwargs)

    class ArticleForm(ModelForm):
        class Meta:
            model = Article
            fields = ["pub_date", "headline", "content", "reporter", "slug"]
            formfield_callback = formfield_for_dbfield

最後に、フィールドを完全に -- タイプ、バリデータ、必須かどうかなどを含めて -- コントロールしたい場合、通常の `Form` で行うのと同じようにフィールドを宣言的に指定することで実現できます。

フィールドのバリデータを指定したい場合、フィールドを宣言的に定義して `validators` パラメータを設定することで実現できます:

    from django.forms import CharField, ModelForm
    from myapp.models import Article

    class ArticleForm(ModelForm):
        slug = CharField(validators=[validate_slug])

        class Meta:
            model = Article
            fields = ["pub_date", "headline", "content", "reporter", "slug"]

注釈

以下のように明示的にフォームフィールドをインスタンス化したとき、`ModelForm` と 通常の `Form` が連動する方法を理解することが重要となります。

`ModelForm` は、特定のフィールドを自動的に生成できる通常の `Form` です。自動的に生成されるフィールドは、`Meta` クラスの内容とどのフィールドが宣言的に定義されているかに依存します。基本的に、`ModelForm` は フォームから 除外された フィールド、言い換えると宣言的に定義されなかったフィールド のみ を生成します。

宣言的に定義されたフィールドはそのままになります。したがって、`Meta` 属性に対するカスタマイズ、例えば `widgets`、`labels`、`help_texts`、`error_messages` は無視されます; これらは自動的に生成されたフィールドにのみ適用されます。

同様に、宣言的に定義されたフィールドは、対応するモデルから引き継がれた `max_length` や `required` のような属性を描画しません。モデル内で定義された動作を引き継ぎたい場合は、フォームフィールドを宣言する際に明示的に関連する属性をセットする必要があります。

例えば、`Article` モデルは以下のようになります:

    class Article(models.Model):
        headline = models.CharField(
            max_length=200,
            null=True,
            blank=True,
            help_text="Use puns liberally",
        )
        content = models.TextField()

そして、指定されたとおりに `blank` と `help_text` が維持されている一方で、`headline` に対して独自のバリデーションを実施するために、`ArticleForm` を以下のように定義します:

    class ArticleForm(ModelForm):
        headline = MyFormField(
            max_length=200,
            required=False,
            help_text="Use puns liberally",
        )

        class Meta:
            model = Article
            fields = ["headline", "content"]

フォームフィールドのタイプを使用して、対応するモデルフィールドの内容を設定できることを確認する必要があります。 互換性がない場合、暗黙的な変換が行われないので、 "ValueError" を取得します。

フィールドとその属性について、詳しくは フォームフィールドのドキュメンテーション を参照してください。

Changed in Django 4.2:

`Meta.formfield_callback` 属性が追加されました。

### フィールドのローカライズを有効にする

デフォルトでは、`ModelForm` 内のフィールドはデータをローカライズしません。フィールドのデータをローカライズするには、`Meta` クラスの `localized_fields` 属性が使用できます。

    >>> from django.forms import ModelForm
    >>> from myapp.models import Author
    >>> class AuthorForm(ModelForm):
    ...     class Meta:
    ...         model = Author
    ...         localized_fields = ['birth_date']

`localized_fields` が特殊な値 `'__all__'` にセットされた場合、全てのフィールドがローカライズされます。

### フォームの継承

基本的なフォームと同様に、 `ModelForms` を継承して拡張したり再利用したりすることができます。これは、モデルから派生した多くのフォームで使用するために、親クラスに追加フィールドや追加メソッドを宣言する必要がある場合に便利です。たとえば、以前の `ArticleForm` クラスを使います:

    >>> class EnhancedArticleForm(ArticleForm):
    ...     def clean_pub_date(self): ...
    ...

これは `ArticleForm` と同じように動作するフォームを作成しますが、`pub_date` フィールドのバリデーションとクリーニングが追加されます。

`Meta.fields` や `Meta.exclude` のリストを変更したい場合は、親の `Meta` インナークラスをサブクラス化することもできます:

    >>> class RestrictedArticleForm(EnhancedArticleForm):
    ...     class Meta(ArticleForm.Meta):
    ...         exclude = ["body"]
    ...

これは `EnhancedArticleForm` からの追加メソッドを追加し、1つのフィールドを削除するようにオリジナルの `ArticleForm.Meta` を修正します。

ただ、注意すべき点がいくつかあります。

- 通常の Python の名前解決ルールが適用されます。内部クラス `Meta` を宣言している基底クラスが複数ある場合、最初のものだけが使用されます。つまり、子クラスの `Meta` が存在する場合はそれが使用され、そうでない場合は最初の親の `Meta` などが使用されます。

- `Form` と `ModelForm` の両方から同時に継承することは可能ですが、必ず `ModelForm` が MRO (Method Resolution Order) の中で最初に現れるようにする必要があります。なぜなら、これらのクラスは異なるメタクラスに依存しており、一つのクラスは一つのメタクラスしか持つことができないからです。

- 親クラスから継承した `Field` を宣言的に削除するには、サブクラスで名前を `None` に設定します。

  このテクニックを使用できるのは、親クラスによって宣言的に定義されたフィールドからオプトアウトする場合のみです。 `ModelForm` メタクラスがデフォルトフィールドを生成するのを防ぐことはできません。デフォルトのフィールドからオプトアウトするには、 使うフィールドを選択する を参照してください。

### 初期値を指定する

通常のフォームと同様に、フォームのインスタンスを作成する際に `initial` パラメータを指定することで、フォームの初期データを指定できます。この方法で指定された初期値は、フォームフィールドからの初期値と、アタッチされたモデルインスタンスからの値の両方を上書きします。たとえば、下記のようにします:

    >>> article = Article.objects.get(pk=1)
    >>> article.headline
    'My headline'
    >>> form = ArticleForm(initial={"headline": "Initial headline"}, instance=article)
    >>> form["headline"].value()
    'Initial headline'

### ModelForm factory 関数

クラス定義ではなく、スタンドアロン関数 `modelform_factory()` を使って、与えられたモデルからフォームを作成することもできます。あまりカスタマイズをしないなら、こちらの方が便利でしょう:

    >>> from django.forms import modelform_factory
    >>> from myapp.models import Book
    >>> BookForm = modelform_factory(Book, fields=["author", "title"])

これは既存のフォームを修正するためにも使用できます。たとえば、指定されたフィールドに使用するウィジェットを指定できます:

    >>> from django.forms import Textarea
    >>> Form = modelform_factory(Book, form=BookForm, widgets={"title": Textarea()})

含むフィールドは `fields` や `exclude` のキーワード引数、もしくは `ModelForm` 内部の `Meta` クラスの対応する属性を使って指定できます。`ModelForm` 使うフィールドを選択する ドキュメントを参照してください。

... 特定のフィールドのローカライズを有効にすることもできます:

    >>> Form = modelform_factory(Author, form=AuthorForm, localized_fields=["birth_date"])

## モデルのフォームセット

class `models.``BaseModelFormSet`

通常のフォームセット のように、 Django は Django モデルでの作業をより便利にするために、いくつかの拡張 フォームセットクラスを提供しています。上の `Author` モデルを再利用してみましょう:

    >>> from django.forms import modelformset_factory
    >>> from myapp.models import Author
    >>> AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])

`fields` を使用すると、フォームセットが指定されたフィールドだけを使うように制限されます。または、除外するフィールドを指定する "オプトアウト" アプローチをとることもできます:

    >>> AuthorFormSet = modelformset_factory(Author, exclude=["birth_date"])

これは `Author` モデルに関連付けられたデータを扱うことができるフォームセットを作成します。通常のフォームセットと同じように動作します:

    >>> formset = AuthorFormSet()
    >>> print(formset)
    <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS"><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS"><input type="hidden" name="form-MIN_NUM_FORMS" value="0" id="id_form-MIN_NUM_FORMS"><input type="hidden" name="form-MAX_NUM_FORMS" value="1000" id="id_form-MAX_NUM_FORMS">
    <div><label for="id_form-0-name">Name:</label><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100"></div>
    <div><label for="id_form-0-title">Title:</label><select name="form-0-title" id="id_form-0-title">
    <option value="" selected>---------</option>
    <option value="MR">Mr.</option>
    <option value="MRS">Mrs.</option>
    <option value="MS">Ms.</option>
    </select><input type="hidden" name="form-0-id" id="id_form-0-id"></div>

注釈

`modelformset_factory()` は `formset_factory()` を使ってフォームセットを生成します。つまり、モデルのフォームセットは基本フォームセットを拡張したもので、特定のモデルとどのように相互作用するかを知っています。

注釈

複数テーブルの継承 を使用している場合、フォームセットファクトリによって生成されたフォームは `id` フィールドの代わりに親リンクフィールド (デフォルトでは `<parent_model_name>_ptr`) を含みます。

### クエリセットを変更する

デフォルトでは、モデルからフォームセットを作成する場合、フォームセットはモデル内のすべてのオブジェクトを含むクエリセットを使用します (例 `Author.objects.all()`) 。 `queryset` 引数を使用することで、この動作をオーバーライドできます:

    >>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith="O"))

もしくは、`__init__` の中で `self.queryset` をセットするサブクラスを作成できます:

    from django.forms import BaseModelFormSet
    from myapp.models import Author

    class BaseAuthorFormSet(BaseModelFormSet):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.queryset = Author.objects.filter(name__startswith="O")

そして、ファクトリ関数に `BaseAuthorFormSet` クラスを渡します:

    >>> AuthorFormSet = modelformset_factory(
    ...     Author, fields=["name", "title"], formset=BaseAuthorFormSet
    ... )

既存のモデルのインスタンスを 一切 含まないフォームセットを返したい場合は、空の QuerySet を指定します:

    >>> AuthorFormSet(queryset=Author.objects.none())

### フォームを変更する

デフォルトでは、 `modelformset_factory` を使うと、 `modelform_factory()` を使ってモデルフォームが作成されます。多くの場合、カスタムモデルフォームを指定すると便利です。たとえば、カスタムバリデーションを持つカスタムモデルフォームを作成できます:

    class AuthorForm(forms.ModelForm):
        class Meta:
            model = Author
            fields = ["name", "title"]

        def clean_name(self):
            # custom validation for the name field
            ...

次に、モデルフォームをファクトリ関数に渡します:

    AuthorFormSet = modelformset_factory(Author, form=AuthorForm)

必ずしもカスタムモデルフォームを定義する必要はありません。 `modelformset_factory` 関数には `modelform_factory` に渡されるいくつかの引数があります。以下で説明します。

### `widgets` を使って、フォームで使用するウィジェットを指定する

パラメータ `widgets` を使うことで、特定のフィールドに対して `ModelForm` のウィジェットクラスをカスタマイズするための値の辞書を指定できます。これは `ModelForm` の内部 `Meta` クラスの `widgets` 辞書と同じように動作します:

    >>> AuthorFormSet = modelformset_factory(
    ...     Author,
    ...     fields=["name", "title"],
    ...     widgets={"name": Textarea(attrs={"cols": 80, "rows": 20})},
    ... )

### `localized_fields` でフィールドのローカライズを有効にする

`localized_fields` パラメータを使って、フォームのフィールドのローカライズを有効にできます。

    >>> AuthorFormSet = modelformset_factory(
    ...     Author, fields=['name', 'title', 'birth_date'],
    ...     localized_fields=['birth_date'])

`localized_fields` が特殊な値 `'__all__'` にセットされた場合、全てのフィールドがローカライズされます。

### 初期値を指定する

通常のフォームセットと同様に、 `modelformset_factory()` によって返されるモデルフォームセットクラスをインスタンス化する際に `initial` パラメータを指定することで、 初期データ をフォームセット内のフォームに指定できます。しかし、モデルフォームセットでは、初期値は既存のモデルインスタンスにアタッチされていない余分なフォームにだけ適用されます。もし `initial` の長さが余分なフォームの数を超えた場合、余分な初期データは無視されます。初期データを持つ余分なフォームがユーザーによって変更されなかった場合、それらはバリデーションも保存もされません。

### フォームセット内のオブジェクトを保存する

`ModelForm` と同様に、データをモデルオブジェクトとして保存できます。これはフォームセットの `save()` メソッドで行います:

    # Create a formset instance with POST data.
    >>> formset = AuthorFormSet(request.POST)

    # Assuming all is valid, save the data.
    >>> instances = formset.save()

`save()` メソッドはデータベースに保存されたインスタンスを返します。指定したインスタンスのデータがバインドされたデータで変更されなかった場合、そのインスタンスはデータベースに保存されず、戻り値 (上記の例では `instances`) にも含まれません。

フォームにフィールドがない場合 (例えば除外されている場合など)、これらのフィールドは `save()` メソッドではセットされません。通常の `ModelForms` にも適用されるこの制限についての詳細は Selecting the fields to use を参照してください。

未保存のモデルインスタンスを返すには `commit=False` を渡します:

    # don't save to the database
    >>> instances = formset.save(commit=False)
    >>> for instance in instances:
    ...     # do something with instance
    ...     instance.save()
    ...

これにより、データベースに保存する前にインスタンスにデータを付加できます。フォームセットに `ManyToManyField` が含まれている場合は、 `formset.save_m2m()` を呼び出して、多対多のリレーションシップが適切に保存されるようにする必要があります。

`save()` を呼び出すと、モデルのフォームセットにはフォームセットの変更を表す3つの新しい属性が追加されます:

`models.BaseModelFormSet.``changed_objects`

`models.BaseModelFormSet.``deleted_objects`

`models.BaseModelFormSet.``new_objects`

### 編集可能なオブジェクトの数を制限する

通常のフォームセットと同様に、 `modelformset_factory()` の `max_num` と `extra` パラメータを使って、表示される追加のフォームの数を制限できます。

`max_num` は既存のオブジェクトが表示されないようにするものではありません:

    >>> Author.objects.order_by("name")
    <QuerySet [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]>

    >>> AuthorFormSet = modelformset_factory(Author, fields=["name"], max_num=1)
    >>> formset = AuthorFormSet(queryset=Author.objects.order_by("name"))
    >>> [x.name for x in formset.get_queryset()]
    ['Charles Baudelaire', 'Paul Verlaine', 'Walt Whitman']

また、 `extra=0` は新しいモデルインスタンスの作成を妨げるものではありません。 JavaScriptでフォームを追加 したり、追加のPOSTデータを送信したりすることができます。この方法については 新しいオブジェクトの作成を防ぐ を参照してください。

もし `max_num` の値が既存の関連オブジェクトの数よりも大きい場合、フォームの総数が `max_num` を超えない限り、最大 `extra` 個の空白のフォームがフォームセットに追加されます:

    >>> AuthorFormSet = modelformset_factory(Author, fields=["name"], max_num=4, extra=2)
    >>> formset = AuthorFormSet(queryset=Author.objects.order_by("name"))
    >>> for form in formset:
    ...     print(form)
    ...
    <div><label for="id_form-0-name">Name:</label><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100"><input type="hidden" name="form-0-id" value="1" id="id_form-0-id"></div>
    <div><label for="id_form-1-name">Name:</label><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100"><input type="hidden" name="form-1-id" value="3" id="id_form-1-id"></div>
    <div><label for="id_form-2-name">Name:</label><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100"><input type="hidden" name="form-2-id" value="2" id="id_form-2-id"></div>
    <div><label for="id_form-3-name">Name:</label><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100"><input type="hidden" name="form-3-id" id="id_form-3-id"></div>

`max_num` の値が `None` (デフォルト) だった場合、表示されるフォームの上限は大きな数になります (1000)。この数は、実際には制限がないと見なせるでしょう。

### 新しいオブジェクトの作成を防ぐ

`edit_only` パラメータを使用すると、新しいオブジェクトを作成しないようにすることができます:

    >>> AuthorFormSet = modelformset_factory(
    ...     Author,
    ...     fields=["name", "title"],
    ...     edit_only=True,
    ... )

ここでは、フォームセットは既存の `Author` インスタンスのみを編集します。他のオブジェクトは作成も編集もされません。

### ビューでモデルフォームセットを使う

モデルのフォームセットはフォームセットにとても似ています。例えば、`Author` モデルのインスタンスを編集するフォームセットを表示したいとしましょう:

    from django.forms import modelformset_factory
    from django.shortcuts import render
    from myapp.models import Author

    def manage_authors(request):
        AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])
        if request.method == "POST":
            formset = AuthorFormSet(request.POST, request.FILES)
            if formset.is_valid():
                formset.save()
                # do something.
        else:
            formset = AuthorFormSet()
        return render(request, "manage_authors.html", {"formset": formset})

見てのとおり、モデルフォームセットのビューロジックは、「通常の」フォームセットと大きく異なるものではありません。唯一の違いは、 `formset.save()` を呼び出してデータをデータベースに保存できることです。(これは上記の フォームセット内のオブジェクトを保存する で説明しています)。

### `ModelFormSet` の `clean()` をオーバーライドする

モデルフォームの `ModelForms` と同様に、デフォルトでは `ModelFormSet` の `clean()` メソッドは、フォームセット内のアイテムがモデルのユニーク制約 (`unique`, `unique_together` または `unique_for_date|month|year`) に違反していないことを検証します。 もし `ModelFormSet` の `clean()` メソッドをオーバーライドし、この検証を維持したい場合は、親クラスの `clean` メソッドを呼び出す必要があります:

    from django.forms import BaseModelFormSet

    class MyModelFormSet(BaseModelFormSet):
        def clean(self):
            super().clean()
            # example custom validation across forms in the formset
            for form in self.forms:
                # your custom formset validation
                ...

また、このステップに到達するまでに、各 `Form` に対して個別のモデルインスタンスが既に作成されていることに注意してください。 `form.cleaned_data` の値を変更するだけでは、保存された値に影響を与えることはできません。 `ModelFormSet.clean()` の値を変更したい場合は、 `form.instance` を変更する必要があります:

    from django.forms import BaseModelFormSet

    class MyModelFormSet(BaseModelFormSet):
        def clean(self):
            super().clean()

            for form in self.forms:
                name = form.cleaned_data["name"].upper()
                form.cleaned_data["name"] = name
                # update the instance value.
                form.instance.name = name

### カスタムのクエリセットを使う

前述のように、モデルのフォームセットで使われるデフォルトのクエリセットはオーバーライドできます:

    from django.forms import modelformset_factory
    from django.shortcuts import render
    from myapp.models import Author

    def manage_authors(request):
        AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])
        queryset = Author.objects.filter(name__startswith="O")
        if request.method == "POST":
            formset = AuthorFormSet(
                request.POST,
                request.FILES,
                queryset=queryset,
            )
            if formset.is_valid():
                formset.save()
                # Do something.
        else:
            formset = AuthorFormSet(queryset=queryset)
        return render(request, "manage_authors.html", {"formset": formset})

この例では `POST` と `GET` の両方で `queryset` 引数を渡していることに注意してください。

### テンプレートでフォームセットを使う

Django テンプレートでフォームセットをレンダリングするには 3 つの方法があります。

1つめは、フォームセットにほとんどの作業を任せる方法です:

    <form method="post">
        {{ formset }}
    </form>

2 つめは、フォームセットを手動でレンダリングして、フォーム自身に処理させる方法です:

    <form method="post">
        {{ formset.management_form }}
        {% for form in formset %}
            {{ form }}
        {% endfor %}
    </form>

手動でフォームをレンダリングする場合は、必ず上記のように管理フォームをレンダリングしてください。 管理フォームのドキュメント を参照してください。

3 つめは、各フィールドを手動でレンダリングする方法です:

    <form method="post">
        {{ formset.management_form }}
        {% for form in formset %}
            {% for field in form %}
                {{ field.label_tag }} {{ field }}
            {% endfor %}
        {% endfor %}
    </form>

この3つめのメソッドを使用し、 `{% for %}` ループでフィールドをイテレートしない場合、主キーフィールドをレンダリングする必要があります。たとえば、モデルの `name` フィールドと `age` フィールドをレンダリングする場合、以下のようにします:

    <form method="post">
        {{ formset.management_form }}
        {% for form in formset %}
            {{ form.id }}
            <ul>
                <li>{{ form.name }}</li>
                <li>{{ form.age }}</li>
            </ul>
        {% endfor %}
    </form>

明示的に `{{ form.id }}` をレンダリングする必要があることに注意してください。これにより、`POST` の場合のモデルのフォームセットが正しく動作するようになります。(この例では `id` という主キーを想定しています。もし `id` という名前ではない独自の主キーを明示的に定義している場合は、それが確実にレンダリングされるようにしてください)。

## インラインフォームセット

class `models.``BaseInlineFormSet`

インラインフォームセットは、モデルフォームセット上の小さな抽象化レイヤーです。これを使うと、外部キーで関連するオブジェクトを操作することが簡単になります。以下の 2 つのモデルがあるとします:

    from django.db import models

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

    class Book(models.Model):
        author = models.ForeignKey(Author, on_delete=models.CASCADE)
        title = models.CharField(max_length=100)

特定の著者の本を編集できるフォームセットを作成したい場合、下記のように書くことができます:

    >>> from django.forms import inlineformset_factory
    >>> BookFormSet = inlineformset_factory(Author, Book, fields=["title"])
    >>> author = Author.objects.get(name="Mike Royko")
    >>> formset = BookFormSet(instance=author)

`BookFormSet` の prefix は `'book_set'` (`<model name>_set`) です。ただし、 `Book` の `Author` への `ForeignKey` に `related_name` がある場合、その名前が代わりに使用されます。

注釈

`inlineformset_factory()` は、 `modelformset_factory()` を使い、`can_delete=True` をセットします。

参考

手動でレンダリングされた can_delete と can_order.

### `InlineFormSet` のメソッドをオーバーライドする

`InlineFormSet` のメソッドをオーバーライドするには、 `BaseModelFormSet` ではなく、 `BaseInlineFormSet` をサブクラス化します。

例えば、 `clean()` をオーバーライドするとします:

    from django.forms import BaseInlineFormSet

    class CustomInlineFormSet(BaseInlineFormSet):
        def clean(self):
            super().clean()
            # example custom validation across forms in the formset
            for form in self.forms:
                # your custom formset validation
                ...

ModelFormSet の clean() をオーバーライドする も参照してください。

そして、インラインフォームセットを作成するときに、オプションの引数 `formset` を渡します:

    >>> from django.forms import inlineformset_factory
    >>> BookFormSet = inlineformset_factory(
    ...     Author, Book, fields=["title"], formset=CustomInlineFormSet
    ... )
    >>> author = Author.objects.get(name="Mike Royko")
    >>> formset = BookFormSet(instance=author)

### 複数の外部キーをひとつのモデルが持っている場合

同じモデルが 1 つよりも多くの外部キーを持っている場合、 `fk_name` を使い手動で曖昧さを解消しなければなりません。例として、次のモデルについて考えます:

    class Friendship(models.Model):
        from_friend = models.ForeignKey(
            Friend,
            on_delete=models.CASCADE,
            related_name="from_friends",
        )
        to_friend = models.ForeignKey(
            Friend,
            on_delete=models.CASCADE,
            related_name="friends",
        )
        length_in_months = models.IntegerField()

これを解決するには、 `inlineformset_factory()` に `fk_name` を使用します:

    >>> FriendshipFormSet = inlineformset_factory(
    ...     Friend, Friendship, fk_name="from_friend", fields=["to_friend", "length_in_months"]
    ... )

### ビューでインラインフォームセットを使う

モデルに紐付いたオブジェクトを編集する機能をユーザーに提供するビューを作るには、こうします:

    def manage_books(request, author_id):
        author = Author.objects.get(pk=author_id)
        BookInlineFormSet = inlineformset_factory(Author, Book, fields=["title"])
        if request.method == "POST":
            formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
            if formset.is_valid():
                formset.save()
                # Do something. Should generally end with a redirect. For example:
                return HttpResponseRedirect(author.get_absolute_url())
        else:
            formset = BookInlineFormSet(instance=author)
        return render(request, "manage_books.html", {"formset": formset})

`POST` と `GET` いずれにおいても `instance` を渡していることに注目してください

### インラインフォームにウィジェットを指定する

`inlineformset_factory` は `modelformset_factory` を使っており、多くの引数は `modelformset_factory` に渡されます。これは `modelformset_factory` と同様に、 `widgets` 引数を渡すことができることを意味しています。詳細は、上記 Specifying widgets to use in the form with widgets を参照してください。