为什么Django DecimalField让我存储Float或字符串?

时间:2018-01-28 10:17:44

标签: python django floating-point decimal

我不理解Django DecimalField的行为。

它被定义为:

  

固定精度十进制数,由Python表示的十进制实例。

但是,使用以下模型:

class Article(models.Model)
    unit_price = DecimalField(max_digits=9, decimal_places=2)

我可以用至少3种方式创建一篇文章:

article = Article.objects.create(unit_price="2.3")
type(article.unit_price)
>>> str

article = Article.objects.create(unit_price=2.3)
type(article.unit_price)
>>> float

article = Article.objects.create(unit_price=Decimal('2.3'))
type(article.unit_price)
>>> decimal.Decimal

为什么Django DecimalField能够返回除Decimal类型以外的其他内容?

确保我的应用程序永远不会处理浮动价格的最佳方法是什么?

感谢。

2 个答案:

答案 0 :(得分:7)

  

为什么Django DecimalField能够返回除Decimal之外的其他内容   类型?

这是因为Django在模型创建过程中是允许的,并且允许您向这些字段输入任何类型而不会错误输出您输入的内容是否可以强制转换为指定的类型。

将其插入数据库后,它将获得正确的类型。您可以使用refresh_from_db()验证这一点:

article = Article.objects.create(unit_price="2.3")
type(article.unit_price)
>>> str
article.refresh_from_db()
type(article.unit_price)
>>> decimal.Decimal
  

确保我的应用永远不会处理花车的最佳方法是什么   价格?

确保这一点的唯一方法是在知道价格金额后立即强制将任何价格输入decimal.Decimal

答案 1 :(得分:1)

嗯,decimal.Decimal子类型本身就是float,这就是为什么它在您的模型中被接受的原因。 decimal.Decimal类型为float类型提供了进一步的算术精度。

如十进制类型docs中所述,操作:

0.1 + 0.1 + 0.1 - 0.3

使用decimal.Decimal精确地给出0,因为在float类型中给出一个接近于零的数字:

5.5511151231257827e-017

最后,decimal.Decimal数字可以完全代表。

  

十进制数是不可变的。它有一个符号,系数数字和   指数。为了保持重要性,系数数字不会   截断尾随零。小数也包括特殊值,如   无穷大,无穷大和NaN。该标准还区分-0   0

为了在您的应用程序中显示小数,您必须也是显式的,并注意十进制转换,每个数据输入/输出或序列化操作使用转换为decimal.Decimal

要进一步深入了解浮点运算在后台的长篇故事,您可以访问此Decimal Arithmetic Specification