Djangoフレームワークには、ウェブ用のFormを作る機能があります。
フォームを使う | Django ドキュメント | Django
フォームを定義して実際にブラウザ上で表示するためには、ビューやテンプレートを用意する必要があるのですが、少しフォームを試したいだけであれば、毎回すべてを用意するのは少し手間です。
フォームクラスの動作を確認するだけであれば、Djangoのrequestオブジェクトには異存しないので、Django shell(manage.py shell)からでも手軽に試せます。
フォームを定義する
適当にmyappというDjangoアプリケーションを作成し、プロジェクトのsettings.LANGUAGEを 'ja'
に変更してからフォームを作ってみます。
myapp/forms.py:
from django import forms class ContactForm(forms.Form): name = forms.CharField(label="お名前", max_length=10) email = forms.EmailField(label="メールアドレス") content = forms.CharField(widget=forms.Textarea)
Django shellから試す
manage.py shell
を起動して、定義しておいた ContactForm
クラスをインポートします。
>>> from myapp.forms import ContactForm
これでContactFormクラスを試す準備ができました。
フォームのインスタンスを作る、メソッドを呼び出す
Djangoのフォームは引数を省略した場合、空のフォーム(新規入力相当)を生成します。
>>> form = ContactForm() >>> form <ContactForm bound=False, valid=Unknown, fields=(name;email;content)> >>> form.as_p() # pタグでフィールドをレンダリングしたHTMLを生成 '<p>\n <label for="id_name">お名前:</label>\n <input type="text" name="name" maxlength="10" required id="id_name">\n \n \n </p>\n\n \n <p>\n <label for="id_email">メールアドレス:</label>\n <input type="email" name="email" maxlength="320" required id="id_email">\n \n \n </p>\n\n \n <p>\n <label for="id_content">Content:</label>\n <textarea name="content" cols="40" rows="10" required id="id_content">\n</textarea>\n \n \n \n \n </p>'
form.as_p()
のようにして、formの各メソッドを試すことができます。
この例だと、pタグでフォームのHTMLを出力するメソッドを試しています。定義したフィールドに対応するHTMLの文字列が生成されていることを確認できます。
入力バリデーションを試す
Djangoのフォームでよく試したいのは、入力バリデーションだと思います。試していきましょう。
Djangoのフォームを使う際に、ビューでは request.POST
のようなオブジェクトを引数で渡していることが多いですが、これは辞書ライクなオブジェクト(QueryDict)です。
実際、Djangoのフォームは入力値としてPythonの辞書を渡せば動かすことができる、シンプルな作りになっています。
formには空の辞書を渡した場合、bound=Trueの状態のフォームインスタンスが作られます。Unbound Form, Bound Formについては、ドキュメントを参照してください。
フォーム API | Django ドキュメント | Django
Bound Formの場合、errorsを参照すると、バリデーションが実行されるので、必須入力のチェックが実行されていることを確認できます。
>>> form = ContactForm({}) >>> form <ContactForm bound=True, valid=Unknown, fields=(name;email;content)> >>> form.errors {'name': ['このフィールドは必須です。'], 'email': ['このフィールドは必須です。'], 'content': ['このフィールドは必須です。']}
nameフィールドの初期値だけを与えてテストしてみましょう。
>>> form = ContactForm({'name': 'おなまえおなまえおなまえ'}) >>> form.is_valid() False >>> form.errors {'name': ['この値は 10 文字以下でなければなりません( 12 文字になっています)。'], 'email': ['このフィールドは必須です。'], 'content': ['このフィールドは必須です。']}
このように、Django shellで、フォームのバリデーションを試すことができます。
cleand_dataを試す
フォームの is_valid()
がTrueを返す状態であれば、 cleaned_data
プロパティでクリーニングしたフィールド毎のデータも取得できます。
フォームフィールドやウィジェットでデータ変換が発生するフォームの場合は、これもDjango shell上で試せるとデバッグがはかどると思います。
>>> form = ContactForm({'name': 'モンティ・パイソン', 'email': 'foo@example.com', 'content': 'お問い合わせ内容'}) >>> form.is_valid() True >>> form.cleaned_data {'name': 'モンティ・パイソン', 'email': 'foo@example.com', 'content': 'お問い合わせ内容'}
IPythonのautoreload
フォームを頻繁に書き換えて試す場合、毎回shellを起動しなおして、インポートからやりなおすのは手間です。
IPythonのshellであれば、autoreloadという拡張を使って少し楽をできるかもしれません。
autoreload — IPython 3.2.1 documentation
IPythonをインストールした状態で、 manage.py shell
を起動すると、IPythonのシェルになります。
%load_ext autoreload
で自動リロードの拡張をロードし、 %autoreload 2
で自動リロードのモードを変更します。
モード2は、「Reload all modules」となっていて、コード実行前に毎回すべてのモジュールがリロードされます。
In [1]: %load_ext autoreload In [2]: %autoreload 2 In [3]: from myapp.forms import ContactForm In [4]: form = ContactForm({}) In [5]: form Out[5]: <ContactForm bound=True, valid=Unknown, fields=(name;email;content)> # ここで、ソースコード内のcontentの行をコメントアウト In [6]: form = ContactForm({}) In [7]: form Out[7]: <ContactForm bound=True, valid=Unknown, fields=(name;email)> # 自動でリロードされたクラスが使われている
プロジェクトが大きいと、毎回全てのモジュールをリロードするのは遅い可能性があるので、その場合はドキュメントにあるように %aimport
を使うなどして、部分的にリロードするだけでもいいかもしれません。
まとめ
Django shellでフォームをインポートして試せることを紹介しました。
最終的にはユニットテストのコードを書いて、保守しやすい状態にするのがよいですが、試行錯誤する段階では、このようにshell上でデバッグする方法も手軽なので、知っておくとよいかなと思います。