Qual é o melhor campo de modelo de django para usar para representar uma quantia em dólares americanos?

104

Preciso armazenar uma quantia em dólares americanos em um campo de um modelo Django. Qual é o melhor tipo de campo de modelo a ser usado? Preciso fazer com que o usuário insira esse valor (com verificação de erro, só quero um número com precisão de centavos), formate-o para saída para usuários em locais diferentes e use-o para calcular outros números.

MikeN
fonte

Respostas:

167

Um campo decimal é a escolha certa para o valor da moeda.

Será algo como:

credit = models.DecimalField(max_digits=6, decimal_places=2)
simplesmente áspero
fonte
99
A menos que você queira representar a dívida nacional, nesse caso max_digits deve ser> 20
Bron Davies
4
decimal_places = 2 não é necessariamente correto se você precisar disso para suportar outras moedas. Algumas moedas têm três casas decimais e o Bitcoin tem 8.
Lie Ryan
2
Acho que este exemplo está correto para quase todas as moedas. Para representar moedas como Bitcoin, acho muito melhor usar um campo inteiro para salvar o valor em satoshis, e depois mostrá-lo ao usuário final na representação que você deseja (BTC, mBTC, etc)
jion
A menos que você queira representar a dívida nacional da Venezuela, na moeda nacional da Venezuela, caso em que você precisa de 21 max_digits
Luis Sieira
@LieRyan isso é verdade. Temos que tomar nota dos tipos modernos de "moeda" para prevenir quaisquer modificações futuras do banco de dados. Sem ofensa pelo uso de aspas.
enchance
35

As outras respostas estão 100% corretas, mas não são muito práticas, pois você ainda terá que gerenciar manualmente a saída, a formatação etc.

Eu sugeriria 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 automaticamente a partir de modelos:

{{ somemodel.some_currency }}

Resultado:

$123.00

Ele tem um back-end poderoso via python-money e é essencialmente um substituto para os campos decimais padrão.

Michael Thompson
fonte
(com verificação de erro, deseja apenas um número com precisão de centavos), formate-o para saída para usuários em locais diferentes e use-o para calcular outros números. Para tais casos, o uso DecimalFieldé mais prático. E acredito que se aplica à maioria das pessoas. Usando django-moneyconforme destacado, inclua o manuseio de moeda . Portanto, isso é mais para projetos envolvendo transações como sites de comércio eletrônico, gateway de pagamento, moeda digital, banco, etc ....
Yeo
Eu diria que, uma vez que eles estão trabalhando com USD - uma moeda - faz mais sentido usar uma biblioteca de manipulação de moeda como django-money (python-money), pois faz tudo funcionar como você espera e permite ajustes de recursos futuros. A pergunta original diz que eles precisam de formatação e cálculo (como você citou) e para isso é melhor usar uma biblioteca de moedas em vez de um simples campo decimal.
Michael Thompson
1
E se eu quiser adicionar dois campos de dinheiro ou fazer alguns cálculos?
saran3h
1
@ saran3h você pode trabalhar com instâncias de dinheiro e realizar cálculos como qualquer outra instância de número (decimal). Você pode adicionar / subtrair, multiplicar por inteiros, etc.
Michael Thompson
9

Defina um decimal e retorne um sinal $ antes do valor.

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

    @property
    def price_display(self):
        return "$%s" % self.price
Çagatay Melan
fonte
6
Você percebe que acabou de criar um loop de recursão infinito em sua propriedade, certo?
El Ninja Trepador de
Interessante. Posso perguntar como é isso?
kingraphaii de
2
field = models.DecimalField(max_digits=8, decimal_places=2)

Deve criar um campo para PostgreSQL como:

 "field" numeric(8, 2) NOT NULL

Qual é a melhor maneira de armazenar o valor em dólares americanos do PostGreSQL.

Se você precisa de um tipo de campo PostgreSQL "precisão dupla", você precisa fazer no modelo django:

field = models.FloatField()
herohat
fonte
3
Cuidado ao representar dinheiro como um número de ponto flutuante, pois as pessoas tendem a ficar insatisfeitas com erros de arredondamento em seu dinheiro. Consulte: stackoverflow.com/questions/3730019/… para obter mais detalhes.
Adam Parkin