103 votes

Django : FloatField ou DecimalField pour les devises ?

Je suis curieux de savoir lequel des deux conviendrait le mieux comme champ monétaire ? Je vais faire des opérations simples comme prendre la différence, le pourcentage entre les anciens et les nouveaux prix. Je prévois de conserver deux chiffres après le zéro (par exemple 10.50) et la plupart du temps, si ces chiffres sont nuls, je les cacherai et les afficherai comme "10".

ps : La monnaie n'est PAS basée sur le dollar :)

168voto

Seth Points 18568

Utilisez toujours DecimalField pour de l'argent. Même les opérations simples (addition, soustraction) ne sont pas à l'abri des problèmes d'arrondis :

>>> 10.50 - 0.20
10.300000000000001

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

7 votes

>>> 10.50 - 0.20 dans Python 2.7 obtenir 10.3 .

9 votes

Eh bien, merde. Je vais devoir migrer beaucoup de données de mes champs/colonnes FloatField vers DecimalField...

0 votes

Il est grand temps que nous ayons une analogie de "n'utilisez pas la virgule flottante pour l'argent" à celle de Bobince. stackoverflow.com/a/1732454/604511

87voto

radtek Points 506

La réponse à la question est correcte, mais certains utilisateurs tomberont par hasard sur cette question pour connaître la différence entre la DecimalField et le FloatField . La question de l'arrondi du flotteur soulevée par Seth est un problème pour les devises.

Les États de la docteure Django

En FloatField est parfois confondue avec la classe DecimalField classe. Bien qu'ils représentent tous deux des nombres réels, ils représentent ces nombres différemment. FloatField utilise l'outil Python float en interne, tandis que DecimalField utilise l'outil Python Decimal type.

Lire la suite aquí .

Voici d'autres différences entre les deux domaines :

DecimalField :

  • DecimalFields doit définir un decimal_places et un max_digits attribut.
  • Vous obtenez deux validations de formulaire libre incluses ici à partir des attributs requis ci-dessus, par exemple si vous définissez max_digits à 4 et vous tapez une décimale qui est 4.00000 (5 chiffres), vous obtiendrez cette erreur : Assurez-vous qu'il n'y a pas plus de 4 chiffres au total.
  • Vous obtenez également une validation de formulaire similaire pour les décimales (qui, dans la plupart des navigateurs, seront également validées sur le front-end à l'aide de l'attribut step du champ de saisie). Si vous définissez decimal_places = 1 et tapez 0.001 comme valeur, vous obtiendrez une erreur indiquant que la valeur minimum doit être 0.1 .
  • Retourne un decimal.Decimal le type est <class 'decimal.Decimal'>
  • Il ne dispose pas de la validation supplémentaire de DecimalField
  • Avec un Decimal l'arrondi est également géré pour vous en raison des attributs requis qui doivent être définis comme décrit ci-dessus. Ainsi, à partir du shell, si vous
  • Dans la base de données (postgresql), l'option DecimalField est enregistré comme un numeric(max_digits, decimal_places) Type, et Storage est défini comme "main", dans l'exemple ci-dessus le Type est numeric(4,1)

En savoir plus DecimalField dans les documents de Django .

FloatField :

  • Renvoie le type de flottant intégré, <type 'float'>
  • Il n'y a pas d'arrondi intelligent, et cela peut même entraîner des problèmes d'arrondi comme décrit dans la réponse de Seth.
  • Il n'y a pas de validation de formulaire supplémentaire, comme c'est le cas avec l'outil de validation des données. DecimalField
  • Dans la base de données (postgresql), l'option FloatField est enregistré comme un type "double précision", et Storage est défini comme "simple".

En savoir plus FloatField dans les documents de Django .

S'applique aux deux :

  • Les deux champs s'étendent de la Field et peut accepter blank , null , verbose_name , name , primary_key , max_length , unique , db_index , rel , default , editable , serialize , unique_for_date , unique_for_month , unique_for_year , choices , help_text , db_column , db_tablespace , auto_created , validators , error_messages comme tous les champs qui s'étendent à partir de Field l'aurait fait.
  • Le widget de formulaire par défaut pour les deux champs est un élément de type TextInput .

Je suis tombé sur cette question en cherchant la différence entre les deux domaines, je pense donc que cela aidera ceux qui sont dans la même situation :)

UPDATE : Pour répondre à la question, je pense que vous pouvez vous en sortir avec l'un ou l'autre pour représenter la monnaie, bien que Decimal est beaucoup plus adapté. Il y a un problème d'arrondi lorsqu'il s'agit d'arrondir les valeurs flottantes. round(value, 2) afin de conserver votre float représentation arrondie à deux décimales. Voici un exemple rapide :

>>> round(1.13 * 50 + .01, 2)
56.51

Vous pouvez toujours avoir des problèmes avec float y round . Comme ici, nous voyons qu'il s'arrondit à la baisse sur une valeur de 5 :

>>> round(5.685, 2)
5.68

Mais dans ce cas, il va arrondir :

>>> round(2.995, 2)
3.0

Cela a tout à voir avec la façon dont le flotteur est stocké en mémoire. Voir aquí .

18voto

Nathan Cox Points 1169

Je sais que c'est très vieux, mais je suis tombé dessus en cherchant quelque chose de complètement différent, et je voulais dire qu'en général, il est déconseillé d'utiliser des nombres à virgule flottante (float). ou décimale) pour la monnaie, car l'arrondi des mathématiques en virgule flottante entraînera invariablement de petites erreurs de calcul qui peuvent s'ajouter à des écarts très importants au fil du temps.

Utilisez plutôt un champ entier ou une chaîne de caractères, selon votre préférence. Multipliez votre monnaie pour déplacer la décimale à la fin et obtenir un nombre entier lorsque vous la stockez, puis remettez cette décimale à sa place lorsque vous devez l'afficher. C'est en gros la façon dont les banques (et la plupart des bibliothèques de devises) gèrent le stockage des données et cela vous évitera bien des soucis par la suite.

J'ai appris cela à la dure parce que ce n'est pas vraiment un sujet courant ; peut-être que cela évitera à quelqu'un d'autre de faire la même chose.

7voto

sxalexander Points 382

edit : Le projet Satchmo n'est plus actif, alors jetez un coup d'oeil à ces alternatives pour gérer la monnaie


L'application Projet Satchmo possède un CurrencyField et un CurrencyWidget qui valent la peine d'être examinés.

Vérifiez le répertoire d'application satchmo_utils pour la source

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X