ラベル formencode の投稿を表示しています。 すべての投稿を表示
ラベル formencode の投稿を表示しています。 すべての投稿を表示

2008年2月28日

formencode.htmlfill

ユーザー入力をチェックしたら、フォームを復元することはよくある話で、エラーメッセージとかも出さないといけないよねと。
Pylonsを含むWSGI派の入力チェックといえば、formencode。
チェックするだけじゃなくて、フォームへの値入れやエラーメッセージ表示に便利なhtmlfillがついている。
htmlに対して適用するから、どんなテンプレートでもOK。


import os
import webob
import tempita
import selector
import formencode
from formencode import validators
from formencode import htmlfill

paths = tempita.bunch()
paths.root = os.path.dirname(__file__)
paths.templates = os.path.join(paths.root, 'templates')

class PersonSchema(formencode.Schema):
name = validators.UnicodeString(not_empty=True)
email = validators.Email(not_empty=True)
blog = validators.URL(not_empty=True)


def form(environ, start_response):
request = webob.Request(environ)
response = webob.Response(request=request, content_type="text/html", charset="utf-8")
tmpl = tempita.HTMLTemplate.from_filename(os.path.join(paths.templates, 'form.html'))
response.body = tmpl.substitute()
return response(environ, start_response)

def submit(environ, start_response):
request = webob.Request(environ)
response = webob.Response(request=request, content_type="text/html", charset="utf-8")
schema = PersonSchema()
try:
params = schema.to_python(request.params)
except formencode.Invalid, e:
errors = e.error_dict
tmpl = tempita.HTMLTemplate.from_filename(os.path.join(paths.templates, 'form.html'))
response.body = htmlfill.render(tmpl.substitute(), defaults=request.params, errors=errors)
else:
tmpl = tempita.HTMLTemplate.from_filename(os.path.join(paths.templates, 'person.html'))
response.body = tmpl.substitute(params=params)
return response(environ, start_response)

application = selector.Selector()
application.add("/", GET=form, POST=submit)


form.htmlはこちら。


<html>
<body>
<form method="post">
<ul>
<li><label for="person-name">Name:</label>
<input id="person-name" type="text" name="name">
<li><label for="person-email">Email:</label>
<input id="person-email" type="text" name="email">
<li><label for="person-blog">Blog:</label>
<input id="person-blog" type="text" name="blog">
</ul>
<button type="submit">Save</button>
</form>
</body>
</html>


form:error というタグを使えば出力位置を調節できる。
対応するform:error がなければ、inputタグの直後にエラーメッセージを表示。
checkboxはboolだけ対応のようだ。

2007年11月11日

FormEncodeでイメージアップロード用のバリデータを作る

FormEncode



さて、FormBuildにしろ、ToscaWidgets(twForm) にしろ、入力チェックにはFormEncodeを使っています。
FormEncodeは、文字列からpythonの値(intや、datetimeなど)に変換と入力チェックを同時にやってくれます。
入力チェックに通った文字列は安全に変換できるってことですね。



標準で、多くのバリデータを含んでいますが、拡張するのも簡単にできるようになっています。
FancyValidatorという、カスタムバリデータを作るための基底クラスも用意されています。
既存のバリデータを継承して、チェック内容を増やすのも簡単です。



ファイルアップロードのバリデータに、FieldStorageUploadConverterがすでにあります。
このバリデータを拡張して、イメージファイル専用のバリデータを作ってみました。



Python Imaging Library



PILと略されて呼ばれることもあります。
Pythonで画像処理をするときに、一番有名なモジュールと思われます。
標準ライブラリに入って欲しいくらいなのだけど、ライセンスの関係からか含まれる予定はありません。
フリーで使えるのは、最新版よりも1つ古いバージョンのものになります。




例えばサムネイルを作って保存するには以下のようになります。

import Image
im = Image.open(filename)
im.thumbnail(size, PIL.Image.ANTIALIAS)
im.save(thumbfilename)

ファイルから、イメージオブジェクトを作って、thumbnailメソッドで変換。
saveメソッドで保存。
というとてもわかりやすいインターフェイスです。



イメージファイルアップロード用のバリデータ



ファイルアップロードされる内容は色々ありますが、イメージファイルのみをアップロード対象とする場合も結構多いと思います。
こういう場合には、ファイルライクオブジェクトが返ってくるより、イメージオブジェクトが返ってくる方が自然に思えます。




FieldStorageUploadConverterを継承して、さらに、イメージに変換する処理を付け加えました。

from formencode import Invalid
from formencode.validators import *
import Image
import os

class ImageFile(FieldStorageUploadConverter):

def _to_python(self, value, state=None):
imagefile = FieldStorageUploadConverter._to_python(self, value, state)
try:
image = Image.open(imagefile.file)
if self.height is not None and image.size[1] > self.height:
raise Invalid('Please image height make less than %d.' % self.height,
value, state)
if self.width is not None and image.size[0] > self.width:
raise Invalid('Please image width make less than %d.' % self.width,
value, state)

return image
except IOError, e:
raise Invalid('Invalid format.', value, state)

これを使うと、Pylonsでrequest.params['image'] などに、Imageオブジェクトが格納されます。
また、ファイルの内容が画像でない(PILで処理できないフォーマット)の場合は、Invalid Format というエラーメッセージが設定されます。
また、バリデータをインスタンス化する際に、コンストラクタに、widthやheightを指定すると、アップロードされた画像のサイズをチェックして、サイズ内に収まっていない場合にバリデーションエラーにします。


参考



追記


サイズチェックを追加しました。