Quel est le meilleur champ de modèle django à utiliser pour représenter un montant en dollars américains?

104

J'ai besoin de stocker un montant en dollars US dans un champ d'un modèle Django. Quel est le meilleur type de champ de modèle à utiliser? Je dois pouvoir demander à l'utilisateur de saisir cette valeur (avec vérification des erreurs, je veux seulement un nombre précis à centimes), la formater pour la sortie aux utilisateurs à différents endroits et l'utiliser pour calculer d'autres nombres.

MikeN
la source

Réponses:

167

UNE champ décimal est le bon choix pour la valeur de la devise.

Cela ressemblera à quelque chose comme:

credit = models.DecimalField(max_digits=6, decimal_places=2)
simplement
la source
100
Sauf si vous souhaitez représenter la dette nationale, auquel cas max_digits doit être> 20
Bron Davies
4
decimal_places = 2 n'est pas nécessairement correct si vous en avez besoin pour prendre en charge d'autres devises. Certaines devises ont trois décimales et Bitcoin a une coqueluche 8.
Lie Ryan
2
Je pense que cet exemple est correct pour presque toutes les devises. Pour représenter les devises sous forme de Bitcoin, je pense qu'il est préférable d'utiliser un champ entier pour enregistrer le montant en satoshis, puis de le montrer à l'utilisateur final dans la représentation que vous souhaitez (BTC, mBTC, etc.)
jion
À moins que vous ne vouliez représenter la dette nationale du Venezuela, dans la monnaie nationale du Venezuela, dans ce cas, vous avez besoin de 21 max_digits
Luis Sieira
@LieRyan c'est vrai. Nous devons prendre note des types modernes de «monnaie» pour empêcher toute modification future de la base de données. Aucune infraction pour l'utilisation de citations.
enchance
35

Les autres réponses sont correctes à 100% mais ne sont pas très pratiques car vous devrez toujours gérer manuellement la sortie, le formatage, etc.

Je suggérerais d'utiliser django-money :

from djmoney.models.fields import MoneyField
from django.db import models


def SomeModel(models.Model):
    some_currency = MoneyField(
        decimal_places=2,
        default=0,
        default_currency='USD',
        max_digits=11,
    )

Fonctionne automatiquement à partir de modèles:

{{ somemodel.some_currency }}

Production:

$123.00

Il a un backend puissant via python-money et c'est essentiellement un remplacement instantané des champs décimaux standard.

Michael Thompson
la source
(avec la vérification des erreurs, ne voulez qu'un nombre précis à centimes), formatez-le pour la sortie aux utilisateurs à différents endroits et utilisez-le pour calculer d'autres nombres. Dans de tels cas, l'utilisation DecimalFieldest plus pratique. Et je pense que cela s'applique à la plupart des gens. En utilisant django-moneycomme ils l'ont mis en évidence, incluez la gestion des devises . Il s'agit donc davantage d'un projet impliquant des transactions telles que des sites de commerce électronique, une passerelle de paiement, une monnaie numérique, des services bancaires, etc.
Yeo
Je dirais que puisqu'ils travaillent avec USD - une devise - il est plus logique d'utiliser une bibliothèque de gestion de devises comme django-money (python-money) car cela fait tout fonctionner comme vous vous y attendez et offre ajustements futurs des fonctionnalités. La question originale dit qu'ils ont besoin d'un formatage et d'un calcul (comme vous l'avez cité) et pour cela, il vaut mieux utiliser une bibliothèque de devises au lieu d'un simple champ décimal.
Michael Thompson
1
Que faire si je veux ajouter deux champs d'argent ou faire des calculs?
saran3h
1
@ saran3h vous pouvez travailler avec des instances money et effectuer des calculs comme n'importe quelle autre instance numérique (décimale). Vous pouvez ajouter / soustraire, multiplier par des entiers, etc.
Michael Thompson
9

Définissez une décimale et renvoyez un signe $ devant la valeur.

    price = models.DecimalField(max_digits=8, decimal_places=2)

    @property
    def price_display(self):
        return "$%s" % self.price
Çagatay Melan
la source
6
Vous réalisez que vous venez de créer une boucle de récursivité infinie dans votre propriété, non?
El Ninja Trepador le
Intéressant. Puis-je demander comment cela?
kingraphaii
2
field = models.DecimalField(max_digits=8, decimal_places=2)

Devrait créer un champ pour PostgreSQL comme:

 "field" numeric(8, 2) NOT NULL

Quel est le meilleur moyen pour PostGreSQL stocké le montant en dollars américains.

Si vous avez besoin d'un champ PostgreSQL de type "double précision", alors vous devez le faire dans le modèle django:

field = models.FloatField()
herohat
la source
3
Méfiez-vous de la représentation de l'argent comme un nombre à virgule flottante, car les gens ont tendance à être mécontents des erreurs d'arrondi de leur argent. Voir: stackoverflow.com/questions/3730019/… pour plus de détails.
Adam Parkin