¿Cuál es el mejor campo de modelo de Django para representar una cantidad en dólares estadounidenses?

103

Necesito almacenar una cantidad de dólares estadounidenses en un campo de un modelo Django. ¿Cuál es el mejor tipo de campo de modelo para usar? Necesito poder hacer que el usuario ingrese este valor (con verificación de errores, solo quiero un número con una precisión de centavos), formatearlo para enviarlo a usuarios en diferentes lugares y usarlo para calcular otros números.

MikeN
fuente

Respuestas:

166

Un campo decimal es la elección correcta para el valor de la moneda.

Se verá algo como:

credit = models.DecimalField(max_digits=6, decimal_places=2)
simplemente dura
fuente
98
A menos que quiera representar la deuda nacional, en cuyo caso max_digits tiene que ser> 20
Bron Davies
4
decimal_places = 2 no es necesariamente correcto si lo necesita para admitir otras monedas. Algunas monedas tienen tres lugares decimales y Bitcoin tiene un 8.
Lie Ryan
2
Creo que este ejemplo es correcto para casi todas las monedas. Para representar monedas como Bitcoin, creo que es mucho mejor usar un campo entero para guardar la cantidad en satoshis, y luego mostrárselo al usuario final en la representación que desee (BTC, mBTC, etc.)
jion
A menos que quiera representar la deuda pública de Venezuela, en la moneda nacional de Venezuela, en cuyo caso necesita 21 max_digits
Luis Sieira
@LieRyan eso es cierto. Tenemos que tomar nota de los tipos modernos de "moneda" para evitar futuras modificaciones de la base de datos. No se ofenda por el uso de comillas.
mejora el
35

Las otras respuestas son 100% correctas, pero no son muy prácticas, ya que aún tendrá que administrar manualmente la salida, el formateo, etc.

Sugeriría usar 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,
    )

Funciona automáticamente a partir de plantillas:

{{ somemodel.some_currency }}

Salida:

$123.00

Tiene un poderoso backend a través de python-money y es esencialmente un reemplazo directo de los campos decimales estándar.

Michael Thompson
fuente
(con verificación de errores, solo desea un número con una precisión de centavos), formatéelo para enviarlo a los usuarios en diferentes lugares y úselo para calcular otros números. Para tales casos, el uso DecimalFieldes más práctico. Y creo que se aplica a la mayoría de las personas. Utilizando django-moneycomo resaltaron, incluya Manejo de moneda . Así que esto es más para proyectos que involucran transacciones como sitios de comercio electrónico, pasarela de pago, moneda digital, banca, etc ....
Yeo
Yo diría que, dado que están trabajando con USD, una moneda, tiene más sentido usar una biblioteca de manejo de monedas como django-money (python-money), ya que hace que todo funcione como cabría esperar y ofrece. futuros ajustes de funciones. La pregunta original dice que necesitan formateo y cálculo (como citó) y para eso es mejor que use una biblioteca de moneda en lugar de un simple campo decimal.
Michael Thompson
1
¿Qué pasa si quiero agregar dos campos de dinero o hacer algunos cálculos?
saran3h
1
@ saran3h puede trabajar con instancias de dinero y realizar cálculos como cualquier otra instancia numérica (decimal). Puede sumar / restar, multiplicar por números enteros, etc.
Michael Thompson
8

Defina un decimal y devuelva un signo $ delante del valor.

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

    @property
    def price_display(self):
        return "$%s" % self.price
Çagatay Melan
fuente
6
Te das cuenta de que acabas de crear un bucle de recursividad infinito en tu propiedad, ¿verdad?
El Ninja Trepador
Interesante. ¿Puedo preguntar cómo es eso?
kingraphaii
2
field = models.DecimalField(max_digits=8, decimal_places=2)

Debería crear un campo para PostgreSQL como:

 "field" numeric(8, 2) NOT NULL

Cuál es la mejor manera para PostGreSQL almacenado en dólares estadounidenses.

Si necesita un tipo de campo de PostgreSQL "doble precisión", entonces debe hacerlo en el modelo django:

field = models.FloatField()
herohat
fuente
3
Tenga cuidado de representar el dinero como un número de punto flotante, ya que las personas tienden a sentirse descontentas con los errores de redondeo de su dinero. Consulte: stackoverflow.com/questions/3730019/… para obtener más detalles.
Adam Parkin