Python Pylons バリデーションのカスタマイズ



Pylonsのバリデーションのカスタマイズを試してみます。
http://wiki.pylonshq.com/pages/viewpage.action?pageId=11174255


まず、メールアドレスの検証方法を変更してみます。

/controllers/hello.py


#インポートを追加
import formencode

#emailメソッドを変更
def email(self):
  schema = EmailForm()
  try:
    #検証実行
    form_result = schema.to_python(request.params)
  except formencode.validators.Invalid, error:
    return 'Invalid: %s' % error
  else:
    return 'Your email is: %s' % form_result.get('email_field')


schema.to_pythonというメソッドを実行することで、
データの検証が行われ、不正なデータである場合は
formencode.validators.Invalidが発生するようです。

そして、errorオブジェクトに

#メールアドレスを入力してね
email_field: Please enter an email address

#入力された文字に@がないよ
email_field: An email address must contain a single @

#@の後にドメイン名がないよ
email_field: The domain portion of the email address is invalid (the portion after the @: )

等など、エラーの内容が入っています。


戻り値のform_resultには、検証後きれいになったデータが
入っているので、検証を通過した場合にはform_resultから
データを取り出し、表示しています。





今まで、標準の
formencode.validators.Email
を使ってメールアドレスの検証を行ってきました。

例えば、「このドメインのアドレス以外はエラーにしたい」
という要件があった場合、クラスを継承してルールを追加すると幸せです。


/lib/form.py
にEmailFormクラスを定義していたかと思いますが、これを
カスタムします。


import formencode

#formencode.validators.Emailを継承したクラスを作成
class SimpleEmail(formencode.validators.Email):
  #_to_pythonというメソッドを追加
  def _to_python(self, value, c):
    #引数c(テンプレートエンジンに渡される変数)の
    #domeinに指定されている値で終了していなかったら
    #エラー発生
    if not value.endswith(c.domain):
      raise formencode.validators.Invalid('Email addresses must end in: %s' % \
                        c.domain, value, c)
    #Email本来の検証を行う
    return formencode.validators.Email._to_python(self, value, c)

#前回作成したクラス
class EmailForm(formencode.Schema):
  allow_extra_fields = True
  filter_extra_fields = True
  
  #検証に使用するクラスを上で定義したSimpleEmailに変更
  #email_field = formencode.validators.Email(not_empty=True)
  email_field = SimpleEmail(not_empty=True)



あわせてコントローラーhello.pyのメソッドを変更

#インポートの追加
import formencode

#HelloControllerクラスのメソッドを変更
def email(self):
  schema = EmailForm()

  #許可するドメインをし愛知
  c.domain = 'example.com'
  try:
    form_result = schema.to_python(request.params, c)
  except formencode.validators.Invalid, error:
    return 'Invalid: %s' % error
  else:
    return 'Your email is: %s' % form_result.get('email_field')


これで、今までのメールアドレスチェックに加え、
example.comドメイン以外のアドレスがエラーに
なるようになりました。





最後に、エラー画面のカスタマイズを行ってみます。


コントローラーhello.pyのemailメソッドをちょっと修正。

def email(self):
  schema = EmailForm()
  c.domain = 'example.com'
  try:
    form_result = schema.to_python(request.params, c)
  except formencode.validators.Invalid, error:
    #return 'Invalid: %s' % error
    
    #テンプレートにエラーの内容を渡す
    c.form_result = error.value
    c.form_errors = error.error_dict or {}
    return render('/form.mako')
  else:
    return 'Your email is: %s' % form_result.get('email_field')



/templates/form.makoをガッツリ変更


${h.form(h.url(action='email'), method='post')}

% if c.form_errors:
<h2>Please correct the errors</h2>
% else:
<h2>Enter Email Address</h2>
% endif

% if c.form_errors:
Email Address: ${h.text_field('email_field', value=c.form_result['email_field'] or '')}
<p>${c.form_errors['email_field']}</p>
% else:
Email Address: ${h.text_field('email_field')}
% endif

${h.submit('Submit')}
${h.end_form()}


動かしてみるとこんな感じです。

初回アクセス時




未入力エラー



ドメインがexample.comじゃない



検証通過




うーん。バリデータークラスやmakoについても
調べないといけませんね。。。





もどる