如何让Django Rest Framework将小数四舍五入到最大精度?

8
我有一个Django Rest Framework序列化器,其中包含一个DecimalField。
serializers.DecimalField(max_digits=9, decimal_places=6)

现在如果我尝试反序列化包含更高精度小数的数据(例如50.1234567),序列化程序会引发一个验证错误:

"Ensure that there are no more than 6 decimal places."

即使最后一位数字为0,这种情况也会发生。是否可以让序列化程序将给定的值四舍五入到最大精度(例如,将50.1234567四舍五入到50.123457)?如果可以,该如何实现?
3个回答

13

将输入强制转换为Decimal后,DecimalField会使用名为validate_precision的方法验证该值的精度,尽管这个方法没有文档。因此,要禁用此验证,可以覆盖此方法并简单地返回输入值:

class RoundingDecimalField(serializers.DecimalField):
    def validate_precision(self, value):
        return value

做到这一点就足以获得所需的舍入行为。

在调用validate_precision之后,DecimalField会调用quantize,它将"将十进制值量化为配置的精度"(来自docstring)。

此量化过程的舍入模式由当前活动的十进制上下文控制。

如果需要特定的舍入模式,则可以使用(同样未记录的)drf_braces.fields.custom.RoundedDecimalField字段,该字段来自django-rest-framework-braces。 此字段采用可选的rounding参数,其中可以指定所需的舍入模式


1
我已经阅读了基类中validate_precision的内容,通过覆盖它,您还禁用了max_digits的检查,而不仅仅是四舍五入,因此在我的情况下,这个解决方案并不理想。事实证明,更好的方法是在serializer.DecimalField实例上只指定decimal_places = None。 - robvdl

2

感谢@jaap3的回答。我想在这里分享我的实现方式,以供其他看到这个问题的人参考。以下是我如何在另一个序列化器类中使用该舍入字段来舍入我想要舍入到Position模型中设置的max_digits值的属性。

class RoundingDecimalField(serializers.DecimalField):
"""Used to automaticaly round decimals to the model's accepted value."""

    def validate_precision(self, value):
        return value


class PositionSerializer(serializers.HyperlinkedModelSerializer):

    url = serializers.HyperlinkedIdentityField(
        view_name='target_position-detail')

    price = RoundingDecimalField(max_digits=21, decimal_places=14)

0
为避免丢失 @robvdl 指出的 validate_precision 的默认实现,我采用了以下解决方案:
class RoundingDecimalField(serializers.DecimalField):

    def validate_precision(self, value):
        # This is needed to avoid to raise an error if `value` has more decimals than self.decimal_places.
        with decimal.localcontext() as ctx:
            if self.rounding:
                ctx.rounding = self.rounding
            value = round(value, self.decimal_places)
        return super().validate_precision(value)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接