フォームを使う¶
このドキュメントについて
このドキュメントでは、Web フォームの基本と、それらを Django で扱う方法を紹介しています。より詳しく知りたいときは、フォーム API の特定の領域、 フォーム API 、 Form fields または フォームとフィールドの検証 をご覧ください。
あなたの作ろうとしているウェブサイトやアプリケーションが、単にコンテンツを公開したり訪問者からのインプットを受け付けないサイトでない限り、フォームを理解し利用する必要があります。
Django は、サイト訪問者からのインプットを受け入れる手助けになるように、幅広いツールとライブラリを提供しており、処理やインプットに対する応答をします。
HTML フォーム¶
HTMLでは、フォームは <form>...</form>
内の要素の集まりで、訪問者によるテキスト入力、オプション選択、オブジェクトやコントロールの操作などを可能にし、これらの情報をサーバーに送り返します。
いくつかのフォームインターフェイスの要素、例えばテキストインプットやチェックボックスは、とてもシンプルで HTML 自体に組み込まれています。そのほかに、とても複雑な要素もあります; Date ピッカーをポップアップさせたり、スライダーを動かしコントロールを操作するようなインターフェイスは、一般的に HTML フォームの <input>
要素だけではなく JavaScriptと CSS を使って実現されます。
As well as its <input>
elements, a form must specify two things:
どこで: ユーザーのインプットに対応するデータの宛先となるべきURL
どのように: データが返される方法として使われるべきHTTPメソッド
例として、Django admin にある複数の <input>
要素のログインフォームを見てみましょう: ユーザー名のための type="text"
、パスワードのための type="password"
、そしてログインボタンのための type="submit"
があります。さらに、Django が次に何をするか決定するために、ユーザーからは見えない非表示のテキストフィールドもあります。
これは、フォームのデータが <form>
の action
属性によって指定された URL - /admin/
- に送信されなければならないこと、そして method
属性によって指定されたHTTP メカニズム - post
- を使って送信されなければならないことを、ブラウザーに通知します。
<input type="submit" value="Log in">
要素がトリガーされると、データは /admin/
に返されます。
GET
と POST
¶
GET
と POST
だけが、フォームを扱うときに使用する HTTP メソッドです。
Django のログインフォームは、POST
メソッドを使って返されます。この中で、ブラウザがフォームデータをひとまとめにし、送信用にエンコードし、サーバーに送った上で、サーバーからの応答を受け取ります。
GET
は、対照的に、送信されたデータを文字列に添付し、URL を構成するために使います。URL はデータが送られるべきアドレスのほか、データキーと値を含みます。実際に、Django ドキュメンテーションで検索してみると、フォーム https://docs.djangoproject.com/search/?q=forms&release=1
といった URL が生成されるのを見ることができます。
GET
と POST
は、主に異なる目的に使われます。
システムの状態を変更する可能性のあるあらゆるリクエスト - 例えばデータベース内での変更を行うリクエスト - では POST
を使うべきです。 GET
は、システムの状態に影響を与えないリクエストのみに使われるべきです。
GET
はパスワードフォームには不適です。なぜならば、パスワードが URL 内はもちろんのこと、ブラウザーの履歴やサーバーログといったプレーンテキストの中すべてに表示されるからです。大量のデータや、画像のようなバイナリデータにも不適です。GET
リクエストを admin フォームのために使ような Web アプリケーションは、セキュリティ上のリスクです: 攻撃者がシステムの繊細な部分へのアクセス権を得るために、フォームのリクエストを偽装することは簡単なのです。Django の CSRF 保護 のような他の保護と組み合わされた POST
は、アクセスをより適切にコントロールできるようにします。
一方で、 GET
は Web 検索フォームのようなものに適しています。なぜならば、 GET
リクエストを表現している URL は、簡単にブックマーク、共有、再送信ができるからです。
フォームでの Django の役割¶
フォームを扱うのは大変な仕事です。Django admin を考えてみると、複数の異なるタイプのデータの、たくさんのアイテムがフォーム内に表示されるために準備を必要とし、HTML としてレンダリングされ、便利なインターフェイスを使って編集され、サーバーに返され、検証され、クリーンアップされます。そして、保存されたり次の処理のために値が渡されたりするのです。
Django のフォーム機能は、この仕事のうち膨大な部分を簡素化・自動化します。そしてさらに、多くのプログラマーたちが自分自身でコードを書くよりも安全にこれらを実現します。
Django は、フォームに含まれる仕事のうち、3つのまったく異なるパーツを扱います:
データがレンダリングできるように準備し、再構成すること
データのために HTML フォームを生成すること
クライアントから送信されたフォームとデータを受け取り、処理すること
これら全ては手動でコードに書くことが できます が、Django がこれらすべてをうまく処理します。
Django におけるフォーム¶
HTML フォームについては簡単に説明しましたが、HTML <form>
は必要となる仕掛けの一部分に過ぎません。
Web アプリケーションの文脈では、 ‘form’ は HTML <form>
、それを提供する Django の Form
、データが送信されたときに返された体系化されたデータ、もしくは端末総合間で動くこれらパーツの集合を意味するかもしれません。
Django の Form
クラス¶
このコンポーネントシステムの中心は、Django の Form
クラスです。 Django モデルがオブジェクトの論理構造、その動作、そしてその部分が私たちに表現される方法を記述するのと同じように、 Form
クラスはフォームを記述し、それがどのように動作し表示されるかを決定します。
モデルクラスのフィールドがデータベースのフィールドに対応するのと同じように、フォームクラスのフィールドは HTML フォームの <input>
要素に対応します。 (ModelForm
はモデルクラスのフィールドと HTML フォームの <input>
要素を、Form
を通じて対応させます; これは Django amin が基づくものです)
フォームのフィールド自体はクラスです; フォームが送信されたとき、フォームデータを管理し、検証を実施します。 DateField
と FileField
は、非常に異なる種類のデータを扱い、異なることをしなければなりません。
フォームフィールドは、HTML “ウィジェット” - ユーザーインターフェイスの装置の一つです - としてブラウザ内のユーザーに表されます。それぞれのフィールドタイプは、適切なデフォルトの Widget class を持っていますが、これらは必要に応じてオーバーライドできます。
フォームをインスタンス化し、処理し、レンダリングする¶
Django でオブジェクトをレンダリングするとき、通常は以下の手順を取ります:
ビューの中でオブジェクトを取得する (例えば、データベースからオブジェクトを取得する)
オブジェクトをテンプレートのコンテクストに引き渡す
テンプレートの変数を使って、オブジェクトを HTML マークアップに展開する
テンプレートの中でフォームをレンダリングすることは、他のあらゆる種類のオブジェクトをレンダリングする働きとほとんど同じですが、いくつかの重要な違いがあります。
データを持たないモデルインスタンスのケースでは、テンプレート内で何かをするのが有益であることはほとんどありません。一方、未入力のフォームをレンダリングすることはまったく合理的です - これは、ユーザーに入力してほしいときに行うことです。
したがって、ビューの中でモデルインスタンスを扱うときには、一般的にデータベースから取り出します。フォームを処理するときには、一般的にビューの中でインスタンス化します。
フォームをインスタンス化するときは、空のままにするかあらかじめ入力しておくことができます。たとえば:
保存されたモデルインスタンスからのデータ (編集のための admin フォームの場合のように)
他のソースから照合したデータ
前回の HTML フォーム送信から受信したデータ
最後のケースが最も興味深いです。なぜならば、それはユーザーが単にウェブサイトを見るだけでなく、情報を送り返すことができるようにするからです。
フォームを作る¶
すべきこと¶
ユーザーの名前を取得するために、ウェブサイトで簡単なフォームを作ることを考えてください。
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" value="OK">
</form>
これは、POST
メソッドを使って、URL /your-name/
にフォームデータを返すよう、ブラウザに通知します。テキストフィールド、”Your name:” ラベル、そして “OK” ボタンを表示します。テンプレートのコンテクストが current_name
変数を含む場合は、 your_name
フィールドをあらかじめ入力するために使われます。
HTML フォームを含むテンプレートをレンダリングし、 current_name
フィールドを適切に提供するビューが必要になります。
フォームが送信されるとき、サーバーに送信される POST
リクエストは、フォームのデータを含みます。
今度は、その /your-name/
URL と対応するビューも必要です。このURLは、リクエストの中から適切なキー/値のペアを見つけ、それらを処理します。
これは非常にシンプルなフォームです。実践では、1つのフォームが数十または数百のフィールドを含んでいて、しかも多くがあらかじめ入力されている必要があるかもしれません。また、操作が完了する前にユーザーが何回も編集と送信を繰り返すことも考えられます。
フォームが送信される前でさえ、ブラウザでいくつかの検証が必要となるかもしれません; ユーザーがカレンダーから日付を選ぶといったような、より複雑なフィールドを使いたくなるかもしれません。
現段階では、Django にこうした仕事をさせるのがとても簡単です。
Django でフォームを作る¶
Form
クラス¶
HTML フォームをどのように見せたいかは、すでに分かっています。Django で実現するためのスタート地点は以下の通りです:
from django import forms
class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)
これは、単一のフィールド (your_name
) で Form
クラスを定義します。人間に優しいラベルをフィールドに適用済みで、このラベルはレンダリングされたときに <label>
のなかに表示されます (このケースでは、仮にラベルの指定を省略したとしても、実際には指定した label
が自動的に生成されるラベルと同じではありますが)。
フィールドの最大文字数は max_length
によって定義されます。これは2つのことをします。HTML の <input>
に maxlength=”100”` を配置します (そしてブラウザはユーザーがこの数値以上の文字数をそもそも入力できないようにするはずです). これはさらに、Django がブラウザからフォームを受け取ったときにデータの文字数を検証することも意味します。
A Form
instance has an is_valid()
method, which runs
validation routines for all its fields. When this method is called, if all
fields contain valid data, it will:
True
を返しますフォームのデータを :attr:`~Form.cleaned_data 属性に配置します
フォーム全体は、初めてレンダリングされたとき、以下のような見た目になります。
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" maxlength="100" required />
<form>
や送信ボタンを含んで いない ことに注意してください。私たち自身が、これらをテンプレート内で提供する必要があります。
ビュー¶
Django ウェブサイトに送り返されたフォームで他は、ビューによって処理されます。通常、ビューはフォームを発行したビューと同じものです。これは、いくつかの同じロジックを再利用することを可能にします。
フォームを処理するためには、フォームを発行したいと考えているURLに対して、ビューの中でインスタンス化する必要があります:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import NameForm
def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
return render(request, 'name.html', {'form': form})
もし GET
とともにビューにたどり着いた場合は、空のフォームインスタンスを生成し、レンダリングのためテンプレートのcontextに配置します。これは、はじめて URL を訪れたときに起こると考えられることです。
POST
リクエストを使ってフォームが送信された場合は、ビューはもう一度フォームインスタンスを生成し、リクエストからのデータを格納します: form = NameForm(request.POST)
これは “フォームにデータをくくりつける” と呼ばれます (そして “くくりつけられた” フォームとなりました)。
フォームの``is_valid()`` メソッドを呼び出します; もし True
でない場合、フォームとともにテンプレートに戻ります。今回はフォームはもはや空にはならない (くくりつけられない) ため、HTML フォームには前回送信されたデータが入力され、必要に応じて編集や修正ができます。
is_valid()
が True
の場合は、 cleaned_data` 属性で検証済みのフォームデータを見出すことができます。このデータは、データベースを更新するために使ったり、次に進むための HTTP リダイレクトをブラウザに送る前に、何らかの処理をできます。
テンプレート¶
name.html
テンプレートでは、すべきことは多くありません。最もシンプルな例は以下の通りです:
<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
すべてのフォームのフィールドと属性は、Django のテンプレート言語によって、この {{ form }}
から HTML マークアップに展開されます。
フォームとクロスサイトリクエストフォージェリ保護
Django は使いやすい クロスサイトリクエストフォージェリに対する保護 を提供しています。有効なCSRF保護とともに POST
を通じてフォームを送信するときには、上記の例にあるように csrf_token
テンプレートタグを使う必要があります。とは言うものの、テンプレートにおいてCSRF 保護はフォームと直接関係あるわけではないので、このドキュメントの以降の例では csrf_token
は省略されています。
HTML5 の input の種類とブラウザ検証
フォームが EmailField
もしくは何か数値のフィールドタイプを含むとき、Django は url
、 email
、 number
という HTML5 の input タイプを使います。デフォルトでは、ブラウザはこれらのフィールドにブラウザ自身の検証を適用します。これらは Django の検証より厳密かもしれません。このような動作を無効化したいときは、 form
タグの novalidate 属性をセットするか、フィールドで TextInput
のような異なるウィジェットを指定してください。
これで、Django の Form
によって記述され, ビューによって処理され、HTML <form>
としてレンダリングされた Web フォームを動かせるようになりました。
始めるために必要なことは以上ですが、フォームフレームワークはまだまだ多くのことを用意しています。上記で説明してきた基本が理解できたら、フォームシステムのほかの機能を理解し、もう少しだけ根本的な仕組みを身につける準備をするようお勧めします。
More about Django Form
classes¶
All form classes are created as subclasses of django.forms.Form
,
including the ModelForm, which you encounter
in Django’s admin.
Models and Forms
In fact if your form is going to be used to directly add or edit a Django
model, a ModelForm can save you a great
deal of time, effort, and code, because it will build a form, along with the
appropriate fields and their attributes, from a Model
class.
Bound and unbound form instances¶
The distinction between Bound and unbound forms is important:
- An unbound form has no data associated with it. When rendered to the user, it will be empty or will contain default values.
- A bound form has submitted data, and hence can be used to tell if that data is valid. If an invalid bound form is rendered, it can include inline error messages telling the user what data to correct.
The form’s is_bound
attribute will tell you whether a form has
data bound to it or not.
More on fields¶
Consider a more useful form than our minimal example above, which we could use to implement “contact me” functionality on a personal website:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
Our earlier form used a single field, your_name
, a CharField
. In
this case, our form has four fields: subject
, message
, sender
and
cc_myself
. CharField
, EmailField
and
BooleanField
are just three of the available field types; a full list
can be found in Form fields.
Widgets¶
Each form field has a corresponding Widget class,
which in turn corresponds to an HTML form widget such as <input
type="text">
.
In most cases, the field will have a sensible default widget. For example, by
default, a CharField
will have a TextInput
widget, that
produces an <input type="text">
in the HTML. If you needed <textarea>
instead, you’d specify the appropriate widget when defining your form field,
as we have done for the message
field.
Field data¶
Whatever the data submitted with a form, once it has been successfully
validated by calling is_valid()
(and is_valid()
has returned True
),
the validated form data will be in the form.cleaned_data
dictionary. This
data will have been nicely converted into Python types for you.
注釈
You can still access the unvalidated data directly from request.POST
at
this point, but the validated data is better.
In the contact form example above, cc_myself
will be a boolean value.
Likewise, fields such as IntegerField
and FloatField
convert
values to a Python int
and float
respectively.
Here’s how the form data could be processed in the view that handles this form:
from django.core.mail import send_mail
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['[email protected]']
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
ちなみに
For more on sending email from Django, see E メールを送信する.
Some field types need some extra handling. For example, files that are uploaded
using a form need to be handled differently (they can be retrieved from
request.FILES
, rather than request.POST
). For details of how to handle
file uploads with your form, see Binding uploaded files to a form.
Working with form templates¶
All you need to do to get your form into a template is to place the form
instance into the template context. So if your form is called form
in the
context, {{ form }}
will render its <label>
and <input>
elements
appropriately.
Form rendering options¶
Additional form template furniture
Don’t forget that a form’s output does not include the surrounding
<form>
tags, or the form’s submit
control. You will have to provide
these yourself.
There are other output options though for the <label>
/<input>
pairs:
{{ form.as_table }}
will render them as table cells wrapped in<tr>
tags{{ form.as_p }}
will render them wrapped in<p>
tags{{ form.as_ul }}
will render them wrapped in<li>
tags
Note that you’ll have to provide the surrounding <table>
or <ul>
elements yourself.
Here’s the output of {{ form.as_p }}
for our ContactForm
instance:
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" required /></p>
<p><label for="id_message">Message:</label>
<textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" required /></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
Note that each form field has an ID attribute set to id_<field-name>
, which
is referenced by the accompanying label tag. This is important in ensuring that
forms are accessible to assistive technology such as screen reader software.
You can also customize the way in which labels and ids are generated.
See Outputting forms as HTML for more on this.
Rendering fields manually¶
We don’t have to let Django unpack the form’s fields; we can do it manually if
we like (allowing us to reorder the fields, for example). Each field is
available as an attribute of the form using {{ form.name_of_field }}
, and
in a Django template, will be rendered appropriately. For example:
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="{{ form.message.id_for_label }}">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="{{ form.sender.id_for_label }}">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>
{{ form.cc_myself }}
</div>
Complete <label>
elements can also be generated using the
label_tag()
. For example:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
Rendering form error messages¶
Of course, the price of this flexibility is more work. Until now we haven’t had
to worry about how to display form errors, because that’s taken care of for us.
In this example we have had to make sure we take care of any errors for each
field and any errors for the form as a whole. Note {{ form.non_field_errors
}}
at the top of the form and the template lookup for errors on each field.
Using {{ form.name_of_field.errors }}
displays a list of form errors,
rendered as an unordered list. This might look like:
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
The list has a CSS class of errorlist
to allow you to style its appearance.
If you wish to further customize the display of errors you can do so by looping
over them:
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
Non-field errors (and/or hidden field errors that are rendered at the top of
the form when using helpers like form.as_p()
) will be rendered with an
additional class of nonfield
to help distinguish them from field-specific
errors. For example, {{ form.non_field_errors }}
would look like:
<ul class="errorlist nonfield">
<li>Generic validation error</li>
</ul>
See フォーム API for more on errors, styling, and working with form attributes in templates.
Looping over the form’s fields¶
If you’re using the same HTML for each of your form fields, you can reduce
duplicate code by looping through each field in turn using a {% for %}
loop:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
Useful attributes on {{ field }}
include:
{{ field.label }}
- The label of the field, e.g.
Email address
. {{ field.label_tag }}
The field’s label wrapped in the appropriate HTML
<label>
tag. This includes the form’slabel_suffix
. For example, the defaultlabel_suffix
is a colon:<label for="id_email">Email address:</label>
{{ field.id_for_label }}
- The ID that will be used for this field (
id_email
in the example above). If you are constructing the label manually, you may want to use this in lieu oflabel_tag
. It’s also useful, for example, if you have some inline JavaScript and want to avoid hardcoding the field’s ID. {{ field.value }}
- The value of the field. e.g
someone@example.com
. {{ field.html_name }}
- The name of the field that will be used in the input element’s name field. This takes the form prefix into account, if it has been set.
{{ field.help_text }}
- Any help text that has been associated with the field.
{{ field.errors }}
- Outputs a
<ul class="errorlist">
containing any validation errors corresponding to this field. You can customize the presentation of the errors with a{% for error in field.errors %}
loop. In this case, each object in the loop is a simple string containing the error message. {{ field.is_hidden }}
- This attribute is
True
if the form field is a hidden field andFalse
otherwise. It’s not particularly useful as a template variable, but could be useful in conditional tests such as:
{% if field.is_hidden %}
{# Do something special #}
{% endif %}
{{ field.field }}
- The
Field
instance from the form class that thisBoundField
wraps. You can use it to accessField
attributes, e.g.{{ char_field.field.max_length }}
.
参考
For a complete list of attributes and methods, see
BoundField
.
Reusable form templates¶
If your site uses the same rendering logic for forms in multiple places, you
can reduce duplication by saving the form’s loop in a standalone template and
using the include
tag to reuse it in other templates:
# In your form template:
{% include "form_snippet.html" %}
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
If the form object passed to a template has a different name within the
context, you can alias it using the with
argument of the include
tag:
{% include "form_snippet.html" with form=comment_form %}
If you find yourself doing this often, you might consider creating a custom inclusion tag.
Further topics¶
This covers the basics, but forms can do a whole lot more:
参考
- The Forms Reference
- Covers the full API reference, including form fields, form widgets, and form and field validation.