11.2.2 cgi モジュールを使う

先頭には "import cgi" と書いてください。"from cgi import *"と書いてはいけません -- このモジュールは以前のバージョンとの互換性を 持たせるために内部で呼び出す名前を多数定義しており、それらが ユーザの名前空間に存在する必要はありません。

新たにスクリプトを書く際には、以下の一行を付加するかどうか検討してください:

import cgitb; cgitb.enable()

これによって、特別な例外処理が有効にされ、エラーが発生した際にブラウザ 上に詳細なレポートを出力するようになります。ユーザにスクリプトの内部を 見せたくないのなら、以下のようにしてレポートをファイルに保存できます:

import cgitb; cgitb.enable(display=0, logdir="/tmp")

スクリプトを開発する際には、この機能はとても役に立ちます。 cgitb が生成する報告はバグを追跡するためにかかる 時間を大きく減らせるような情報を提供してくれます。スクリプトを テストし終わり、正確に動作することを確認した後はいつでも cgitb の行を削除できます。

入力されたフォームデータを取得するには、 FieldStorage クラス を使うのが最良の方法です。このモジュールで定義されている他のクラスの ほとんどは以前のバージョンとの互換性のためのものです。 インスタンス生成は引数なしで必ず 1 度だけ行います。これにより、 標準入力または環境変数からフォームの内容が読み出されます (どちらから読み出されるかは、CGI 標準に従って設定されている 複数の環境変数の値によって決められます)。インスタンスが標準入力を 使うかもしれないので、インスタンス生成を行うのは一度だけにしなければ なりません。

FieldStorage のインスタンスは Python の辞書のようにインデクス を使った参照ができ、標準の辞書に対するメソッド has_key()keys() をサポートしています。組み込みの関数 len() もサポートされています。空の文字列を含むフォームのフィールドは 無視され、辞書上にはありません; そういった値を保持するには、 FieldStorage のインスタンスを生成する時にオプションの keep_blank_values キーワード引数を true に設定してください。

例えば、以下のコード (Content-Type: ヘッダと空行は すでに出力された後とします) は name および addr フィールドが両方とも空の文字列に設定されていないか調べます:

form = cgi.FieldStorage()
if not (form.has_key("name") and form.has_key("addr")):
    print "<H1>Error</H1>"
    print "Please fill in the name and addr fields."
    return
print "<p>name:", form["name"].value
print "<p>addr:", form["addr"].value
...further form processing here...

ここで、"form[key]" で参照される各フィールドは それ自体が FieldStorage (または MiniFieldStorage 。 フォームのエンコードによって変わります) のインスタンスです。 インスタンスの属性 value フィールドの文字列値になります。 getvalue() メソッドはこの文字列値を直接返します。 getvalue() は 2 つめの引数にオプションの値を与えることが でき、リクエストされたキーが存在しない場合に返されるデフォルトの 値になります。

入力されたフォームデータに同じ名前のフィールドが二つ以上あれば、 "form[key]" で得られるオブジェクトは FieldStorageMiniFieldStorage のインスタンスではなく、それらインスタンスから なるリストになります。同じく、この状況では、 "form.getvalue(key)" は文字列を要素とするリストを返します。 もしこうした状況が起こりうると思われるなら (HTML のフォームに同じ名前をもったフィールドが複数含まれているのなら) 、 組み込み関数 getlist() を使ってください。この関数は 常に値のリストを返します (従って、要素が単一の場合を特別扱い しなくて済みます)。 例えば、以下のコードは任意の数のユーザ名フィールドを 結合し、コンマで分割された文字列にします:

value = form.getlist("username", "")
usernames = ",".join(value)

フィールドがアップロードされたファイルを表す場合、value 属性または getvalue() メソッドを介してアクセスされた 値はファイルの内容を全て文字列としてメモリ上に読み込みます。 これは望ましくない機能かもしれません。アップロードされたファイルが あるかどうかは filename 属性および file 属性の いずれかで調べることができます。その後、以下のようにして file 属性から落ち着いてデータを読み出せます:

fileitem = form["userfile"]
if fileitem.file:
    # It's an uploaded file; count lines
    linecount = 0
    while 1:
        line = fileitem.file.readline()
        if not line: break
        linecount = linecount + 1

現在ドラフトとなっているファイルアップロードの標準仕様では、一つの フィールドから (再帰的な multipart/* エンコーディングを 使うことで) 複数のファイルがアップロードされる可能性を受け入れています。 この場合、アイテムは辞書形式の FieldStorage アイテムと なります。複数ファイルかどうかは type 属性が multipart/form-data (または multipart/* に マッチする他の MIME 型) になっているかどうか調べることで判別できます。 この場合、トップレベルのフォームオブジェクトと同様にして再帰的に 個別処理できます。

フォームが ``古い'' 形式で入力された場合 (クエリ文字列または application/x-www-form-urlencoded データの単一の部分の場合) アイテムは実際には MiniFieldStorage クラスのインスタンス になります。この場合、listfile 、および filename 属性は常に None になります。

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。