wiki:spa00

SPA00(第0回Python温泉)に参加しました

2007年6月22-24に伊豆で行われたPythonユーザの合宿、SPA00(通称Python温泉)に、 弊社の金本、吉田、中川、中居、増田が参加しました。

増田のレポート

  • 弊社から無線LAN環境を提供しようと意気込んでAirMacExtremeを持ち込んだのですが、会議室のインフラが 無線LANのみ、かつWDS非対応で断念。2個もっていけばよかった...
  • ほとんどの時間をPython/Django関係の物書きに費やしました。Djangoユーザ率が高かったので、その場で 質問して回答をもらえて助かりました。「Django組」のみなさんありがとう!
  • 途中、newformsの使い方(form_for_model, form_for_instance)の使い方で質問が出たので簡単にレクチャー。

newformsのキモ

  • newforms でフォームクラスを作るには、2つの方法がある。
  • Form クラスをサブクラス化して、カスタムのフォームクラスを作る。検索フォームのように、特定のモデルクラスに 関わらないフォームはこっちの方法を使う。
  • form_for_model や form_for_instance を使って、モデルやインスタンスを introspection させてフォームクラスを生成させる。 モデルインスタンスのCreate/Update/Deletionに絡むインタフェースは、こっちを使う。
  • フォームクラスのインスタンスを生成するには、2つの方法がある。
  • 引数を渡さずにFormインスタンスを生成すると、フォームは 非束縛(特定のデータに結びついていない)フォーム になる。 非束縛フォームは、いわば初めてフォームの入ったページを表示するときの内容を出力するためのフォーム。 非束縛フォームはバリデーションしないし、is_validとか clean() しても意味がない。

  • 引数(辞書とか request.POST/GET) を渡してインスタンスを生成すると、フォームは 束縛(特定のデータに結びつけられた)フォーム になる。束縛フォームは、フォームインスタンスを生成するときに渡された データ(束縛データ)を検証して、Pythonオブジェクトに変換する。 (一般に、「バリデーション」過程には、人間のようなデータソースから入力されたデータの検証を行うとともに、コントローラ 側でハンドリング可能な形式に(たとえば文字列から数値へ)変換する役割がある)。 束縛フォームに対して errorsを参照するか、is_valid() を呼び出すと検証が行われる(同時に、変換後の値が clean_data(SVN版ではcleaned_data)に入る。バリデーションしないかぎり、 clean() も clean(ed)_data も エラーになるから注意。 (0.96と開発版は名前が違うので、互換性を持たせたければ clean() を呼んで辞書を返させるといいよ。)

  • というわけで、newformsを使ったフォームのロジックは基本的に以下のようになる:

    class MyForm(forms.Form):
        ... (適当にフォームクラス定義)
    
    def my_form_view(request):
        if request.POST:
            form = MyForm(reqest.POST)  # ここで束縛フォームを作っている。
            if form.is_valid():
                cleaned_values_dict = form.clean()
                ...
                return HttpResponseRedirect(...) # (フォーム処理がうまくいったので)結果のページを表示したり、リダイレクトで飛ばしたりする。
        else:
            form = MyForm() # POSTデータがないから非束縛フォームを作る。
        # Context の form には、(1)検証エラーに失敗した束縛フォームか、(2)POSTデータの入っていない非束縛フォームが入っている。
        # (1) だとバリデーションエラー付きのHTMLフラグメントが、 (2) だと初期値の入った HTML フラグメントが出力される。
        return render_to_response(template_name, Context(dict(form=form))
    
  • form_for_model と form_for_instance は CRUD に使う。

    • CReate の場合には、まだ編集すべきインスタンスがないから、フォームの初期値はインスタンス生成時のデフォルト値を 使うのが適当だよね?つまり、 form_for_model を使う。
    • Update/Delete の場合には、編集すべきインスタンスの値がフォームに入っているべき。だから、 form_for_instance を使う。
    • form_for_model/form_for_instance を使ってると、フィールドの一部で期待はずれのフォームウィジェットが出てくる。 この問題は、 formfield_callback を定義して回避する といいよ。でも、めんどくさい!
  • APIを定義すると、ハンドラリストとDispatcherを返せるインスタンスを生成できるようなメタクラスのアイデア。 まだ実装してない。(その場で話を聞いていた人のblogを読む限り、内容が非常に誤解されているようだ)