Django check: Use DecimalField for currency

Use DecimalField instead of FloatField for representing currency in your model. FloatField is susceptible to rounding errors.

Description

Use DecimalField instead of FloatField for representing currency in your model. FloatField is susceptible to rounding errors.

According to the Django documentation, the FloatField class is sometimes mixed up with the DecimalField class. Although they both represent real numbers, they represent those numbers differently. FloatField uses Python’s float type internally, while DecimalField uses Python’s Decimal type. For information on the difference between the two, see Python’s documentation for the decimal module.

Example:

>>> 10.50 - 0.20
10.300000000000001

>>> Decimal('10.50') - Decimal('0.20')
Decimal('10.30')

This check will alert on cases where the field name contains any of the following keywords: price, amount, subtotal, donation, fee, salary, or precio; and the field set to FloatField.

from django.db import models
from django.utils import timezone

class Product(models.Model):
    title = models.CharField(max_length=64)
    description = models.TextField()

    # DecimalField is ok
    price = models.DecimalField(max_digits=6, decimal_places=2)

    # this field name contains "price", it should have used DecimalField
    old_price = models.FloatField()
    image = models.CharField(max_length=256)
    stock = models.IntegerField(null=True)
    date_added = models.DateTimeField(default=timezone.now)

References

  1. Django documentation: FloatField vs. DecimalField
  2. Python documentation: decimal
  3. Stackoverflow discussion