python - template - Django: ¿cómo debo almacenar un valor monetario?
django templates examples (8)
Me encuentro con un problema de paradigma aquí. No sé si debería guardar dinero como un decimal (), o si debería almacenarlo como una cadena y convertirlo a un decimal yo mismo. Mi razonamiento es este:
PayPal requiere 2 posiciones decimales , por lo que si tengo un producto que es de 49 dólares, incluso, PayPal quiere ver que 49.00 se crucen con el cable. Django''s DecimalField () no establece una cantidad decimal. Solo almacena una cantidad máxima de decimales. Entonces, si tienes 49 allí, y tienes el campo configurado en 2 lugares decimales, todavía lo almacenará como 49. Sé que Django es básicamente de tipo fundido cuando se deserializa desde la base de datos a un decimal (ya que las bases de datos no tienen campos decimales), así que no estoy tan preocupado con los problemas de velocidad como con los problemas de diseño de este problema. Quiero hacer lo mejor para la extensibilidad.
O, mejor aún, ¿alguien sabe cómo configurar un django DecimalField () para formatear siempre con el estilo de formato TWO_PLACES?
Basándose en la respuesta de @Will_Hardy, aquí está para que no tenga que especificar max_dígitos y decimales cada vez:
from django.db import models
from decimal import Decimal
class CurrencyField(models.DecimalField):
__metaclass__ = models.SubfieldBase
def __init__(self, verbose_name=None, name=None, **kwargs):
super(CurrencyField, self). __init__(
verbose_name=verbose_name, name=name, max_digits=10,
decimal_places=2, **kwargs)
def to_python(self, value):
try:
return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
except AttributeError:
return None
Creo que deberías almacenarlo en formato decimal y formatearlo en formato 00.00 solo para luego enviarlo a PayPal, así:
pricestr = "%01.2f" % price
Si lo desea, puede agregar un método a su modelo:
def formattedprice(self):
return "%01.2f" % self.price
El dinero debe almacenarse en el campo de dinero, que lamentablemente no existe. Dado que el dinero es un valor bidimensional (cantidad, moneda).
Hay lib lib de python , que tiene muchas bifurcaciones, pero no he encontrado ninguna.
Recomendaciones:
python-money probablemente el mejor tenedor https://bitbucket.org/acoobe/python-money
django-money recomendado por akumria: http://pypi.python.org/pypi/django-money/ (aún no lo he probado).
En mi experiencia y también de others , el dinero se almacena mejor como combinación de moneda y la cantidad en centavos.
Es muy fácil de manejar y calcular con él.
Mi última versión de la fiesta que agrega migraciones al sur.
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''])
Sugiero evitar mezclar representación con almacenamiento. Almacene los datos como un valor decimal con 2 lugares.
En la capa UI, muéstrela en una forma que sea adecuada para el usuario (así que quizás omita el ".00").
Cuando envíe los datos a PayPal, formatéelos como lo requiere la interfaz.
Usted lo almacena como un DecimalField y agrega manualmente los decimales si es necesario, como dijo Valya, usando técnicas básicas de formateo.
Incluso puede agregar un Método de modelo a su producto o modelo de transacción que escupirá el DecimalField como una cadena con el formato adecuado.
Es posible que desee utilizar el método .quantize()
. Esto redondeará un valor decimal a un cierto número de lugares, el argumento que proporciona especifica el número de lugares:
>>> from decimal import Decimal
>>> Decimal("12.234").quantize(Decimal("0.00"))
Decimal("12.23")
También puede tomar un argumento para especificar qué método de redondeo desea (diferentes sistemas contables pueden querer un redondeo diferente). Más información en los documentos de Python .
A continuación se muestra un campo personalizado que produce automáticamente el valor correcto. Tenga en cuenta que esto es solo cuando se recupera de la base de datos, y no lo ayudará cuando lo configure usted mismo (¡hasta que lo guarde en el db y lo recupere nuevamente!).
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
[editar]
agregó __metaclass__
, vea Django: ¿Por qué este campo de modelo personalizado no se comporta como se esperaba?