129

I need to store a U.S. $ dollar amount in a field of a Django model. What is the best model field type to use? I need to be able to have the user enter this value (with error checking, only want a number accurate to cents), format it for output to users in different places, and use it to calculate other numbers.

MikeN
  • 42,547
  • 47
  • 147
  • 224

5 Answers5

227

A decimal field is the right choice for the currency value.

It will look something like:

credit = models.DecimalField(max_digits=6, decimal_places=2)
user8193706
  • 2,115
  • 2
  • 6
  • 12
simplyharsh
  • 33,714
  • 12
  • 61
  • 70
  • 147
    Unless you want to represent the national debt, in which case max_digits has to be > 20 – Bron Davies Aug 17 '16 at 14:44
  • 4
    decimal_places=2 is not necessarily correct if you need this to support other currencies. Some currencies have three decimal places, and Bitcoin has a whooping 8. – Lie Ryan Jan 13 '18 at 13:29
  • 2
    I think this example is correct almost to all currencies. To represent currencies as Bitcoin, I think is much better to use an integer field to save the amount in satoshis, and then show it to the final user in the representation that you want (BTC, mBTC, etc) – jion Jan 21 '18 at 06:01
  • @LieRyan that's true. We have to take note of modern types of "currency" to prevent any future db modifications. No offence for the use of quotes. – enchance Mar 04 '20 at 07:02
  • @BronDavies SAVAGE – NoName Jun 15 '20 at 21:21
  • 3
    This answer https://stackoverflow.com/questions/224462/storing-money-in-a-decimal-column-what-precision-and-scale/ suggests using `max_digits=19, decimal_place=4` to be safe. – Boris Verkhovskiy Jul 23 '20 at 20:14
50

The other answers are 100% right but aren't very practical as you'll still have to manually manage output, formatting etc.

I would suggest using 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,
    )

Works automatically from templates:

{{ somemodel.some_currency }}

Output:

$123.00

It has a powerful backend via python-money and it's essentially a drop-in replacement for standard decimal fields.

Michael Thompson
  • 4,011
  • 1
  • 29
  • 23
  • *(with error checking, only want a number accurate to cents), format it for output to users in different places, and use it to calculate other numbers.* For such cases, use `DecimalField` is more practical. And I believe it is applied for most people. Using `django-money` as they highlighted, include **Currency** handling. So this is more for project involving transaction such as ecommerce sites, payment gateway, digital currency, banking, etc.... – Yeo Jul 19 '16 at 22:34
  • I'd argue that since they're working with USD -- a currency -- it makes more sense to use a currency-handling library like django-money (python-money) as it makes everything work as you'd expect and affords future feature adjustments. The original question says they need formatting and calculation (as you quoted) and for that you're better off using a currency library instead of a simple decimal field. – Michael Thompson Jul 20 '16 at 02:30
  • 1
    What if I want to add two money fields or do some calculations? – saran3h Jul 10 '18 at 04:42
  • 2
    @saran3h you can work with money instances and perform calculations like any other number (decimal) instance. You can add/subtract, multiply by integers, etc. – Michael Thompson Jul 12 '18 at 16:42
44
field = models.DecimalField(max_digits=8, decimal_places=2)

Note that max_digits should be >= decimal_places. This example setting would allow a value up to: 999,999.99

Docs: https://docs.djangoproject.com/en/1.10/ref/models/fields/#decimalfield

Lee Hinde
  • 983
  • 11
  • 13
9

Define a decimal and return a $ sign in front of the value.

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

    @property
    def price_display(self):
        return "$%s" % self.price
J__
  • 596
  • 5
  • 20
cmelan
  • 249
  • 5
  • 13
2
field = models.DecimalField(max_digits=8, decimal_places=2)

Should create a field for PostgreSQL like:

 "field" numeric(8, 2) NOT NULL

Which is the best way for PostGreSQL stored US dollar amount.

If you need a PostgreSQL field type "double precision", then you need do in django model:

field = models.FloatField()
manuelpgs
  • 903
  • 10
  • 19
  • 3
    Beware of representing money as a floating point number, as people tend to get unhappy about rounding errors w.r.t. their money. See: https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency for more details. – Adam Parkin Oct 03 '18 at 22:00