66 votes

Django: Comment dois-je stocker une valeur monétaire?

Je suis en cours d'exécution dans un paradigme de problème ici. Je ne sais pas si je doit stocker de l'argent en tant que nombre Décimal(), ou si je doit le stocker en tant que chaîne et de le convertir en décimal moi-même. Mon raisonnement est le suivant:

PayPal nécessite 2 décimales, donc si j'ai un produit qui est de 49 dollars même, PayPal veut voir 49.00 venir à travers le fil. Django DecimalField() ne définit pas une décimale. Il ne stocke un maximum de décimales montant. Donc, si vous avez 49 là, et vous avez le champ défini à 2 décimales, ça va encore le stocker en tant que 49. Je sais que Django est essentiellement de type casting quand il désérialise de retour à partir de la base de données en Décimal (depuis les Bases de données n'ont pas de champs décimaux), donc je ne suis pas complètement concernés par les problèmes de vitesse autant que je le suis avec les problèmes de conception de ce problème. Je veux faire ce qui est mieux pour l'extensibilité.

Ou, mieux encore, personne ne sait comment configurer un django DecimalField() pour toujours format avec le TWO_PLACES style de mise en forme.

65voto

Will Hardy Points 6663

Vous pouvez utiliser l' .quantize() méthode. Ce sera le tour d'une valeur décimal à un certain nombre de lieux, l'argument que vous fournissez spécifie le nombre de place:

>>> from decimal import Decimal
>>> Decimal("12.234").quantize(Decimal("0.00"))
Decimal("12.23")

Il peut aussi être un argument pour spécifier ce que l'arrondi de l'approche que vous voulez (différents systèmes de comptabilité pourrait vouloir différentes arrondi). Plus d'infos dans le Python docs.

Ci-dessous est un champ personnalisé qui produit automatiquement à la valeur correcte. Notez que ce n'est que lorsqu'il est extrait de la base de données, et wont vous aider lorsque vous définissez vous-même (jusqu'à ce que vous l'enregistrez dans la base de données et de les récupérer à nouveau!).

from django.db import models
from decimal import Decimal
class CurrencyField(models.DecimalField):
    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        try:
           return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
        except AttributeError:
           return None

[modifier]

ajouté __metaclass__, voir Django: Pourquoi ce modèle de champ se comporte pas comme prévu?

18voto

Valentin Golev Points 5002

Je pense que vous devriez stocker dans un format décimal et le format au format 00.00 ne puis l' envoyer à PayPal, comme ceci:

 pricestr = "%01.2f" % price
 

Si vous le souhaitez, vous pouvez ajouter une méthode à votre modèle:

 def formattedprice(self):
    return "%01.2f" % self.price
 

13voto

so_ Points 141

Mon retard à la version du parti qui ajoute des migrations Sud.

 from decimal import Decimal
from django.db import models

try:
    from south.modelsinspector import add_introspection_rules
except ImportError:
    SOUTH = False
else:
    SOUTH = True

class CurrencyField(models.DecimalField):
    __metaclass__ = models.SubfieldBase

    def __init__(self, verbose_name=None, name=None, **kwargs):
        decimal_places = kwargs.pop('decimal_places', 2)
        max_digits = kwargs.pop('max_digits', 10)

        super(CurrencyField, self). __init__(
            verbose_name=verbose_name, name=name, max_digits=max_digits,
            decimal_places=decimal_places, **kwargs)

    def to_python(self, value):
        try:
            return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
        except AttributeError:
            return None

if SOUTH:
    add_introspection_rules([
        (
            [CurrencyField],
            [],
            {
                "decimal_places": ["decimal_places", { "default": "2" }],
                "max_digits": ["max_digits", { "default": "10" }],
            },
        ),
    ], ['^application\.fields\.CurrencyField'])
 

12voto

aisbaa Points 1202

L'argent doit être stocké dans le domaine de l'argent, qui, malheureusement, n'existe pas. Puisque l'argent est en deux dimensions de la valeur (montant, devise).

Il y a python-argent lib, qui a beaucoup de fourches, mais je n'ai pas trouvé de travail.


Recommandations:

python d'argent, probablement le meilleur de la fourche https://bitbucket.org/acoobe/python-money

django-argent recommandé par akumria: http://pypi.python.org/pypi/django-money/ (nai pas essayé encore).

10voto

Aaron Digulla Points 143830

Je suggère d'éviter de mélanger la représentation avec le stockage. Stocker les données sous forme décimale avec 2 places.

Dans la couche d'interface utilisateur, affichez-le sous une forme qui convient à l'utilisateur (omettez peut-être le ".00").

Lorsque vous envoyez les données à PayPal, formatez-les comme le requiert l'interface.

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