【问题标题】:Decimal field rounding in WTFormsWTForms 中的小数字段舍入
【发布时间】:2016-02-12 17:52:28
【问题描述】:

我有一个包含价格小数字段的表单,如下所示:

from flask.ext.wtf import Form
import wtforms
from wtforms.validators import DataRequired
from decimal import ROUND_HALF_UP

class AddListingBase(Form):
    title = wtforms.StringField(validators=[DataRequired()])
    details = wtforms.TextAreaField(validators=[DataRequired()])
    price = wtforms.DecimalField(places=2, rounding=ROUND_HALF_UP, validators=[DataRequired()])

当我提交表单时,十进制值被假定为四舍五入到小数点后 2 位,但这从未发生过。我总是得到指定的值(例如,99.853 是 99.853,而不是应该的 99.85)。

【问题讨论】:

  • 我查看了github.com/wtforms/wtforms/blob/… 的代码,这些参数仅应用于值提供 用作起始值(_values 函数),而不是用于输入( _process_formdata 函数)。所以你必须推出自己的验证器。
  • @mueslo 就是答案,所以将其添加为一个!

标签: python wtforms flask-wtforms


【解决方案1】:

正如@mueslo 正确推断的那样,这是因为默认的DecimalField 实现不会对它接收到的表单数据进行四舍五入。它只对初始数据进行四舍五入(如 defaultsmodel/saved data)。

我们可以通过修改后的 DecimalField 实现轻松更改此行为,其中我们覆盖 process_formdata 方法。有点像这样:

from wtforms import DecimalField


class BetterDecimalField(DecimalField):
    """
    Very similar to WTForms DecimalField, except with the option of rounding
    the data always.
    """
    def __init__(self, label=None, validators=None, places=2, rounding=None,
                 round_always=False, **kwargs):
        super(BetterDecimalField, self).__init__(
            label=label, validators=validators, places=places, rounding=
            rounding, **kwargs)
        self.round_always = round_always

    def process_formdata(self, valuelist):
        if valuelist:
            try:
                self.data = decimal.Decimal(valuelist[0])
                if self.round_always and 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)
                    self.data = quantized
            except (decimal.InvalidOperation, ValueError):
                self.data = None
                raise ValueError(self.gettext('Not a valid decimal value'))

示例用法:

rounding_field = BetterDecimalField(round_always=True)

Gist

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多