WTForms中的十进制字段舍入

KRT*_*Tac 5 python wtforms flask-wtforms

我有一个包含价格十进制字段的表单,如下所示:

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()])
Run Code Online (Sandbox Code Playgroud)

当我提交表单时,小数值被赋予舍入到2位小数,但这种情况从未发生过.我总是得到指定的值(例如99.853是99.853,而不是应该是99.85).

boo*_*dev 6

正如@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'))
Run Code Online (Sandbox Code Playgroud)

用法示例:

rounding_field = BetterDecimalField(round_always=True)
Run Code Online (Sandbox Code Playgroud)

要旨