python.django.correctness.use-decimalfield-for-money.use-decimalfield-for-money

profile photo of semgrepsemgrep
Author
4,873
Download Count*

Found a FloatField used for variable $F. Use DecimalField for currency fields to avoid float-rounding errors.

Run Locally

Run in CI

Defintion

rules:
  - id: use-decimalfield-for-money
    patterns:
      - pattern-inside: |
          class $M(...):
            ...
      - pattern: $F = django.db.models.FloatField(...)
      - metavariable-regex:
          metavariable: $F
          regex: .*([pP][rR][iI][cC][eE]|[aA][mM][oO][uU][nN][tT]|[sS][uU][bB][tT][oO][tT][aA][lL]|[dD][oO][nN][aA][tT][iI][oO][nN]|[fF][eE][eE]|[sS][aA][lL][aA][rR][yY]|[pP][rR][eE][cC][iI][oO]).*
    message: Found a FloatField used for variable $F. Use DecimalField for currency
      fields to avoid float-rounding errors.
    languages:
      - python
    severity: ERROR
    metadata:
      category: correctness
      technology:
        - django
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]

Examples

use-decimalfield-for-money.py

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

# Create your models here.

class Product(models.Model):
    title = models.CharField(max_length=64)
    description = models.TextField()
    # ok:use-decimalfield-for-money
    price = models.DecimalField(max_digits=6, decimal_places=2)
    # ruleid:use-decimalfield-for-money
    old_price = models.FloatField()
    image = models.CharField(max_length=256)
    stock = models.IntegerField(null=True)
    date_added = models.DateTimeField(default=timezone.now)
    # ruleid:use-decimalfield-for-money
    orignalPrice = models.FloatField(verbose_name=u"smth")

class User(models.Model):
    email = models.EmailField()
    password = models.CharField(max_length=32)

    gender = models.BooleanField()
    first_name = models.CharField(max_length=32)
    last_name = models.CharField(max_length=32)

    postal_code = models.CharField(max_length=16)
    house_number_additions = models.CharField(max_length=16)
    street_name = models.CharField(max_length=64)
    city_name = models.CharField(max_length=32)
    country = models.CharField(max_length=32)

    phone_number = models.CharField(max_length=16)
    date_of_birth = models.DateField()