【问题标题】:WTForms How to use a DecimalField which generates proper field errors on bad inputWTForms 如何使用在错误输入时生成正确字段错误的 DecimalField
【发布时间】:2013-02-28 06:35:13
【问题描述】:

看看这个例子

class MyForm(ForM):
    ...snip...
    quantity = DecimalField(u'Quantity', [NumberRange(1, 8)])
    ...snip...

如果用户合作并输入可以强制转换为数字类型的内容,这会很好地工作。但是,如果用户在浏览器的此字段中输入“asdf”,那么当我尝试在浏览器中呈现它时,DecimalField 会抛出 Type Error

以下是回溯的相关部分:

Traceback (most recent call last):
    File "/path/to/app/venv/local/lib/python2.7/site-packages/jinja2/environment.py", line 894, in render
      return self.environment.handle_exception(exc_info, True)
    File "/path/to/app/www/templates/submodule/user/submission.html", line 26, in block "submodule_content"
      {{form.quantity}}
    File "/path/to/app/venv/local/lib/python2.7/site-packages/wtforms/fields/core.py", line 139, in __call__
      return self.widget(self, **kwargs)
    File "/path/to/app/venv/local/lib/python2.7/site-packages/wtforms/widgets/core.py", line 123, in __call__
      kwargs['value'] = field._value()
    File "/path/to/app/venv/local/lib/python2.7/site-packages/wtforms/fields/core.py", line 542, in _value
      return format % self.data
TypeError: a float is required

我希望字段本身添加一个错误,而不是这种行为,以便我仍然可以渲染 t。

我目前的解决方案包括使用TextField 而不是DecimalField 并提供IsNumeric 验证器,其调用方法如下:

def __call__(self, form, field):
    if field.data:
        try:
            field.data = float(field.data)
        except ValueError as e:
            raise ValidationError(self.message)

这几乎完美无缺,是我目前的解决方案,但肯定有一种 wtforms 惯用的方式来做到这一点。

【问题讨论】:

  • 您如何向表单提供表单数据(您如何构建它)?它是使用表单数据多字典提供的吗?如果是这样,则不应发生此错误,因为不应将数据强制转换为 .data 属性。这通常发生在人们将原始表单数据作为 **kwargs 传递时,这应该只用于已经强制的数据。
  • 是的,这是使用 **kwargs 样式。 **kwargs 的文档中没有任何内容表明它们应该已经被强制,并且使用 web.py(可能还有其他 Web 框架),这就是返回参数的方式。应该采取什么强制措施,是否有理由认为 **kwargs 的处理方式与 multi-dict 不同?大多数情况下,最好在文档中明确说明。

标签: python wtforms type-coercion


【解决方案1】:

我不得不处理类似的问题。 SelectMultipleFieldcoerce=text_type(这是默认的 kwarg)将输入数据转换为 str/unicode。这意味着它“强制”None(当用户没有选择任何内容时输入我的字段的值)到"None" - 这是调试的巨大痛苦。您的问题清楚地表明,不只是我参与了 wtforms 内部验证过程。

我找到的正确解决方案是,您编写 StringField(textfield) 的自定义子类并覆盖 __call__process_dataprocess_formdata 方法以满足您的需求。 __call__ 用于将它们渲染成 html(这应该由另一个 widget 可调用完成),process_data 通常用于从 python 对象获取数据(这意味着服务器端),process_formdata 就像 process_data除了它处理用户提交的表单。或者,如果您想要 DRY(不要重复自己),您可以覆盖 __init__ 并将您的自定义验证器设为默认值。

编辑:

DecimalField 的愚蠢代码是导致TypeError 的原因。看看它的_value() 方法,DecimalField 的渲染小部件使用该方法来为<input type="text" ... value=X> 获取X

def _value(self):
    if self.raw_data:
        return self.raw_data[0]
    elif self.data is not None:
        if self.places is not None: # <-- this line brings you the pain
            if hasattr(self.data, 'quantize'):
                exp = decimal.Decimal('.1') ** self.places
                if self.rounding is None:
                    quantized = self.data.quantize(exp)
                else:
                    quantized = self.data.quantize(exp, rounding=self.rounding)
                return text_type(quantized)
            else:
                # If for some reason, data is a float or int, then format
                # as we would for floats using string formatting.
                format = '%%0.%df' % self.places
                return format % self.data
        else:
            return text_type(self.data)
    else:
        return ''

它在创建字段时声明field.data - field.places 的类型之前检查field.places,并且只是说您需要N 位精度;它并不表示您有 N 位 Decimal 作为您的 fields.data,但 wtforms 开发人员以某种方式决定检查 field.places 足以假设该字段包含相应的浮点数。 (代码检查field.data 上是否有quantize 属性,但仅适用于小数)

我认为你必须编写自己的DecimalField 子类。这是我编写DecimalField 的非白痴版本的尝试:

from wtforms.fields.core import DecimalField as _DecimalField

class DecimalField(_DecimalField):
  def _value(self):
    try:
      float(self.data) #check whether you have a 'number'
      return super(DeciamlField, self)._value()
    except (TypeError, ValueError): #self.data is 'None', 'asdf' ...
      return text_type(self.data) if self.data else ''

【讨论】:

  • 当然这是使用DecimalField 的一般情况吗?你的解决方案很好,但仍然需要我编写自己的 wtforms 扩展,因为我惊讶地发现这不是默认行为。
  • 你能发布你的回溯吗?
  • 这是从 google 获得的好信息(不过,我更感兴趣的是找到在框架内运行良好的东西)。我提交了关于该项目的问题:bitbucket.org/simplecodes/wtforms/issue/146/…
猜你喜欢
  • 1970-01-01
  • 2013-09-19
  • 2011-05-02
  • 2014-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多