Django フォーム
HTMLフォームは、Webサイトのインタラクティブ性を実現する古典的な方法です。この章では、Djangoを使用してユーザーが送信したフォームデータを処理する方法を紹介します。
HTTP リクエスト
HTTPプロトコルは「リクエスト-レスポンス」の方式で動作します。クライアントがリクエストを送信する際、リクエストにデータを添付できます。サーバーはリクエストを解析することで、クライアントから送られてきたデータを取得し、URLに基づいて特定のサービスを提供します。
GET メソッド
以前のプロジェクトに search.py ファイルを作成して、ユーザーのリクエストを受け取ります:
/HelloWorld/HelloWorld/search.py ファイルコード:
テンプレートディレクトリ templates に search_form.html フォームを追加します:
/HelloWorld/templates/search_form.html ファイルコード:
urls.py のルールを次のように変更します:
/HelloWorld/HelloWorld/urls.py ファイルコード:
アクセスアドレスhttp://127.0.0.1:8000/search-form/そして検索すると、結果は次のようになります:

POST メソッド
上記では GET メソッドを使用し、ビューの表示とリクエスト処理を2つの関数に分けて処理しました。
データを送信する際は、POST メソッドがより一般的に使用されます。以下ではこのメソッドを使用し、1つのURLと処理関数で、ビューの表示とリクエスト処理を同時に行います。
templates に post.html を作成します:
/HelloWorld/templates/post.html ファイルコード:
テンプレートの末尾に、フォーム処理結果のためのプレースホルダーとして rlt マーカーを追加します。
フォームの後ろにはもう1つ{% csrf_token %}のタグがあります。csrf の正式名称は Cross Site Request Forgery です。これは Django が提供する、偽装リクエストの送信を防ぐ機能です。POST メソッドで送信されるフォームには、このタグが必須です。
HelloWorld ディレクトリに search2.py ファイルを新規作成し、search_post 関数を使用して POST リクエストを処理します:
/HelloWorld/HelloWorld/search2.py ファイルコード:
urls.py のルールを次のように変更します:
/HelloWorld/HelloWorld/urls.py ファイルコード:
アクセスhttp://127.0.0.1:8000/search-post/表示結果は次のとおりです:
上記のインスタンスを完了すると、ディレクトリ構造は次のようになります:
HelloWorld
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- search.py
| |-- search.pyc
| |-- search2.py
| |-- search2.pyc
| |-- settings.py
| |-- settings.pyc
| |-- testdb.py
| |-- testdb.pyc
| |-- urls.py
| |-- urls.pyc
| |-- views.py
| |-- views.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- TestModel
| |-- __init__.py
| |-- __init__.pyc
| |-- admin.py
| |-- admin.pyc
| |-- apps.py
| |-- migrations
| | |-- 0001_initial.py
| | |-- 0001_initial.pyc
| | |-- __init__.py
| | `-- __init__.pyc
| |-- models.py
| |-- models.pyc
| |-- tests.py
| `-- views.py
|-- db.sqlite3
|-- manage.py
`-- templates
|-- base.html
|-- hello.html
|-- post.html
`-- search_form.html
Request オブジェクト
各ビュー関数の最初のパラメータは HttpRequest オブジェクトです。次の サンプル() 関数のように:
from django.http import HttpResponse
def サンプル(request):
return HttpResponse("Hello world")
HttpRequest オブジェクトには、現在のリクエストURLに関する情報が含まれます:
|
属性 |
説明 |
|
path |
リクエストされたページのフルパスで、ドメイン名は含みません。例: "/hello/"。 |
|
method |
リクエストで使用されるHTTPメソッドの文字列表現。大文字で表されます。例: if request.method == 'GET': |
|
GET |
すべてのHTTP GETパラメータを含む辞書風オブジェクト。QueryDict ドキュメントを参照してください。 |
|
POST |
すべてのHTTP POSTパラメータを含む辞書風オブジェクト。QueryDict ドキュメントを参照してください。 サーバーが空のPOSTリクエストを受け取る場合も起こり得ます。つまり、フォームがHTTP POSTメソッドでリクエストを送信しても、フォームにはデータがない場合があります。したがって、if request.POST を使用してHTTP POSTメソッドかどうかを判断することはできません。if request.method == "POST" を使用すべきです(この表のmethod属性を参照)。 注意: POST にはファイルアップロード情報は含まれません。FILES属性を参照してください。 |
|
REQUEST |
便宜上、この属性はPOST属性とGET属性を合わせたものですが、特殊な点があり、最初にPOST属性を探し、次にGET属性を探します。PHPの$_REQUESTを参考にしています。 例えば、GET = {"name": "john"} かつ POST = {"age": '34'} の場合、REQUEST["name"] の値は "john"、REQUEST["age"] の値は "34" です。 GET と POST を使用することを強くお勧めします。これらの2つの属性の方がより明示的で、書かれたコードも理解しやすくなります。 |
|
COOKIES |
すべてのCookieを含む標準のPython辞書オブジェクト。キーと値は両方とも文字列です。 |
|
FILES |
すべてのアップロードファイルを含む辞書風オブジェクト。FILES の各キーは <input type="file" name="" /> タグの name 属性の値です。FILES の各値も標準のPython辞書オブジェクトであり、次の3つのキーを含みます:
注意:リクエストメソッドがPOSTであり、リクエストページ内の <form> に enctype="multipart/form-data" 属性がある場合のみ、FILES はデータを持ちます。それ以外の場合、FILES は空の辞書です。 |
|
META |
利用可能なすべてのHTTPヘッダー情報を含む辞書。例:
META では、これらのヘッダーに接頭辞HTTP_を付けたものが Key となり、コロン(:)の後ろが Value となります。例:
|
|
user |
django.contrib.auth.models.User オブジェクトであり、現在ログインしているユーザーを表します。 アクセスユーザーが現在ログインしていない場合、user は django.contrib.auth.models.AnonymousUser のインスタンスとして初期化されます。 user の is_authenticated() メソッドを使用して、ユーザーがログインしているかどうかを判断できます:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
Django の AuthenticationMiddleware がアクティブな場合にのみ、この属性は使用可能です。 |
|
session |
唯一読み書き可能な属性で、現在のセッションを表す辞書オブジェクトです。Django のセッションサポートがアクティブな場合にのみ使用可能です。 |
|
raw_post_data |
未解析の生のHTTP POSTデータ。高度な処理の際に役立ちます。 |
Request オブジェクトには便利なメソッドもいくつかあります:
| メソッド | 説明 |
|---|---|
| __getitem__(key) | GET/POST のキーに対応する値を返します。先にPOSTを取得し、次にGETを取得します。キーが存在しない場合は KeyError を送出します。 これにより、辞書構文を使用して HttpRequest オブジェクトにアクセスできます。 例えば、request["foo"] は、最初に request.POST["foo"] を実行し、次に request.GET["foo"] を実行する操作と同じです。 |
| has_key() | request.GET または request.POST にパラメータで指定されたKeyが含まれているかどうかを確認します。 |
| get_full_path() | クエリ文字列を含むリクエストパスを返します。例: "/music/bands/the_beatles/?print=true" |
| is_secure() | リクエストが安全な場合、Trueを返します。つまり、HTTPSリクエストが送信された場合です。 |
QueryDict オブジェクト
HttpRequestオブジェクトでは、GETおよびPOST属性はdjango.http.QueryDictクラスのインスタンスです。
QueryDictは辞書に似たカスタムクラスで、1つのキーが複数の値に対応する場合を処理するために使用されます。
QueryDictは標準の辞書メソッドをすべて実装しています。さらに、いくつかの特有のメソッドも含まれます:
| メソッド | 説明 |
|---|---|
|
__getitem__ |
標準の辞書の処理とは少し異なり、Keyが複数のValueに対応する場合、__getitem__()は最後のvalueを返します。 |
|
__setitem__ |
パラメータで指定されたkeyのvalueリスト(Pythonのリスト)を設定します。注意:これはmutable(変更可能な)QueryDictオブジェクトでのみ呼び出すことができます(つまり、copy()によって生成されたQueryDictオブジェクトのコピーです)。 |
|
get() |
keyが複数のvalueに対応する場合、get()は最後のvalueを返します。 |
|
update() |
パラメータはQueryDictでも標準の辞書でもかまいません。標準の辞書のupdateメソッドとは異なり、このメソッドは辞書のitemsを置き換えるのではなく追加します:
>>> q = QueryDict('a=1')
>>> q = q.copy() # to make it mutable
>>> q.update({'a': '2'})
>>> q.getlist('a')
['1', '2']
>>> q['a'] # returns the last
['2']
|
|
items() |
標準の辞書のitems()メソッドとは少し異なり、このメソッドは単一値ロジックの__getitem__()を使用します:
>>> q = QueryDict('a=1&a=2&a=3')
>>> q.items()
[('a', '3')]
|
|
values() |
標準の辞書のvalues()メソッドとは少し異なり、このメソッドは単一値ロジックの__getitem__()を使用します: |
さらに、QueryDictには次の表に示すようないくつかのメソッドもあります:
| メソッド | 説明 |
|---|---|
|
copy() |
オブジェクトのコピーを返します。内部実装はPython標準ライブラリのcopy.deepcopy()を使用します。このコピーはmutable(変更可能)です。つまり、このコピーの値を変更できます。 |
|
getlist(key) |
パラメータのkeyに対応するすべての値をPythonリストとして返します。keyが存在しない場合は空のリストを返します。何らかのリストを返すことが保証されています。 |
|
setlist(key,list_) |
keyの値をlist_に設定します(__setitem__()とは異なります)。 |
|
appendlist(key,item) |
keyに関連付けられた内部リストにitemを追加します。 |
|
setlistdefault(key,list) |
setdefaultとは少し異なり、単一のvalueではなくリストをパラメータとして受け取ります。 |
|
lists() |
items()とは少し異なり、keyのすべての値をリストとして返します。例:
>>> q = QueryDict('a=1&a=2&a=3')
>>> q.lists()
[('a', ['1', '2', '3'])]
|
|
urlencode() |
クエリ文字列形式でフォーマットされた文字列を返します(例:"a=2&b=3&b=5")。 |