如何向Flatland Form类添加表单级验证?

时间:2010-12-02 22:36:12

标签: python forms

我有一个代理网站的flatland表单,如下所示:

class doSomethingForm(Form):
  '''Do an action with account credentials'''
  username = String.using(default='',
    validators=[Present(), UsernameFormat()])
  password = String.using(default='',
    validators=[Present(), PasswordFormat()])
  action = String.using(default='',
    validators=[Present(), ActionFormat()])

如果任何参数为空,我希望验证错误是给定元素为空。如果它们非空并满足其他要求,则下一步是询问其他服务是否有效。如果它们无效,那么我想将其转换为验证错误。

这看起来很像flatland的容器级验证,它首先对包含的元素进行验证。所以我尝试了这个:

class doSomethingForm(Form):
  '''Do an action with account credentials'''
  account = Dict.of(
    username = String.named('username').using(default='',
      validators=[Present(), UsernameFormat()])
    password = String.named('password').using(default='',
      validators=[Present(), PasswordFormat()])
  ).using(validators=[CheckCredentials()])
  action = String.using(default='',
    validators=[Present(), ActionFormat()])

这看起来会起作用,但现在表单正在寻找名为account_usernameaccount_password的元素,这不是我希望的接口。

我看到了几个解决方案:

  1. 我可以将CheckCredentials验证程序附加到doSomethingForm。但是,我没有在文档中看到这样做的方法。
  2. 我可以将CheckCredentials验证程序附加到usernameaccess its sibling password。但是,如果用户名和密码格式不正确,我不想打扰其他服务器。所以我必须首先在usernamepassword上运行验证,这似乎重复了我自己。
  3. 我可以破解Dict的一个没有命名空间
  4. 的版本

    有没有正确的方法在flatland中添加表单级验证器?

2 个答案:

答案 0 :(得分:1)

在阅读了一些文档后,我认为你可以简单地做your_form.validate()

Form类继承Dict类,因此验证方式与容器级验证通常的工作方式相同。

免责声明:直到你的问题,我从未听说过“平地”,所以我真的可以离开这里。

答案 1 :(得分:1)

检查flatland代码(hg clone http://bitbucket.org/jek/flatland)非常有用,因为文档和示例还不完整。

Form继承自Dict,继承自Container,继承自Element。有两个类元素可以提供帮助:

  • descent_validators(来自Container) - 一个可以在下降(第一)阶段运行的可验证器的迭代。
  • validators(来自Element) - 可在上升(第二)阶段运行的可验证器的迭代。

要获得我想要的行为(仅在用户名和密码有效时检查帐户),我需要将验证器添加到validators类变量,并检查子验证器是否已通过。

我的代码现在看起来像这样:

class CheckCredentials(Validator):
  '''Checks credentials and creates an account object'''

  def validate(self, element, state):
    username = element['username']
    password = element['password']
    if not (username.all_valid and password.all_valid):
      return false

    self.account = Account(username.u, password.u)
    return self.account.valid()


class doSomethingForm(Form):
  '''Do an action with account credentials'''
  username = String.using(default='',
    validators=[Present(), UsernameFormat()])
  password = String.using(default='',
    validators=[Present(), PasswordFormat()])
  action = String.using(default='',
    validators=[Present(), ActionFormat()])

  validators = (CheckCredentials(),)

@expose('/do_something')
def doSomething(request):
  form = doSomethingForm.from_defaults()
  form.set_flat(request.form)

  result_html = ''
  method = request.method
  if method == 'POST' and not form.validate():
    method = 'GET'
    errors = []
    if form.errors: errors.extend(form.errors)
    for el in form.all_children:
      if el.errors: errors.extend(el.errors)
    result_html = errorsToHtml(errors)

  if method == 'POST':
    result_html = form.account.action(form['action'].u)

  return render_template('do_something.html',
    result=result_html, **form.value)

我认为flatland可以做一些更酷的事情来帮助生成HTML表单,但到目前为止我对此非常满意。

感谢WoLpHjek的帮助。