11.1.2 cgiモジュールを使う

まず最初に"import cgi"が必要です。 "from cgi import *"では駄目です -- あなたの名前空間では必要でないあらゆる種類の名前が、 モジュール自身と互換性のために定義されています。

FieldStorageクラスを使うのがベストです。 このモジュールで定義される他のクラスは、ほとんどが互換性のために提供されています。 FieldStorageクラスは確実に一度だけ、引数なしでインスタンス化されなければなりません。 これでフォームの内容が標準入力か環境(変数)から読み取られます。 (どちらの方法で読み取られるかは、CGI標準にしたがって設定されたいろいろな環境変数に依存します。) 標準入力が使われることがあるので、インスタンス化は一度だけなのです。

FieldStorageインスタンスはパイソンの辞書のように扱えます。 例えば、次のコードではnameaddrフィールドは 両方空ではないことをチェックしています。 (Content-typeヘッダと空行はこの前に出力されているものとします。):

form = cgi.FieldStorage()
form_ok = 0
if form.has_key("name") and form.has_key("addr"):
    if form["name"].value != "" and form["addr"].value != "":
        form_ok = 1
if not form_ok:
    print "<H1>Error</H1>"
    print "Please fill in the name and addr fields."
    return
...この後にフォームの処理が続く...

このform[key]で参照されるフィールドは、 FieldStorageインスタンス自身です。 (あるいは、フォームのエンコード方法に依存しますが、MiniFieldStorageかも)

フォームが同じ名前のフィールドを複数含んでいた場合には、form[key](Mini)FieldStorageインスタンスではなく、インスタンスのリストになります。 こうなる可能性があるときは (同じ名前のフィールドが複数あるような HTMLフォームを使う場合には)、 type()関数でインスタンスかそのリストかを調べてください。 例えば、いくつかのユーザ名のフィールドをコンマで区切る場合のコードは:

username = form["username"]
if type(username) is type([]):
    # Multiple username fields specified
    # 複数のユーザ名が入っている場合
    usernames = ""
    for item in username:
        if usernames:
            # Next item -- insert comma
            # 次のアイテム -- コンマを挿入
            usernames = usernames + "," + item.value
        else:
            # First item -- don't insert comma
            # 最初のアイテム -- コンマは入れない
            usernames = item.value
else:
    # Single username field specified
    # ユーザ名が一つしかない
    usernames = username.value

フィールドがファイルのアップロードを示している場合、 ファイルが丸ごと文字列としてメモリに読み込まれます。 これは本意ではないかもしれません。 そんなときは、filename属性か、file属性を見ることによってアップロードされたファイルを 調べることができます。 そうすれば安心(reasure?)して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/*を使う) 複数のファイルのアップロードの可能性について述べています。 この場合は、アイテムは辞書のような FieldStrageアイテムとなるでしょう。 そのときは typemultipart/form-data(または多分、multipart/で始まる別の文字列) という値を持っているべきです。 この場合、アップロードされたものは、 最上位の formオブジェクトのような再帰的な繰り返しになります。

フォームが、「古い」フォーマットで(query stringか application/x-www-form-urlencoded の単一データとして)送信された場合、アイテムは 実際 MiniFieldStorageクラスのインスタンスに なるでしょう。 この場合、ファイル・ファイル名属性のリストはいつも Noneです。

guido@python.org