[Django]-What is the best django model field to use to represent a US dollar amount?

254đź‘Ť

âś…

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)
👤simplyharsh

55đź‘Ť

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.

45đź‘Ť

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

8đź‘Ť

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
👤cmelan

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

1đź‘Ť

You can use django-money for money field:

First, install django-money[exchange] as shown below:

pip install django-money[exchange]

*You can install django-money without [exchange] as shown below but it doesn’t have the functions to convert currencies so I recommend to install django-money[exchange] as shown above:

pip install django-money

Next, add 'djmoney.contrib.exchange' to INSTALLED_APPS in core/settings.py:

# "core/settings.py"

INSTALLED_APPS = [
    ...,
    'djmoney.contrib.exchange',
]

Then, run the command below:

python manage.py migrate

Then, define a field with MoneyField(), MinMoneyValidator(), MaxMoneyValidator() and Decimal in MyModel model in `my_app/models.py’ as shown below:

# "my_app/models.py"

from djmoney.models.fields import MoneyField
from decimal import Decimal
from djmoney.models.validators import MaxMoneyValidator, MinMoneyValidator

class MyModel(models.Model):
    money = MoneyField(
        max_digits=5, decimal_places=2, default=0, default_currency='USD',
        validators=[
            MinMoneyValidator(Decimal(0.00)), MaxMoneyValidator(Decimal(999.99)),
        ]
    )

Then, run the command below:

python manage.py makemigrations && python manage.py migrate

Then, you can add a value on Django Admin as shown below:

enter image description here

Then, you can get the value with $ and the value without $ using .amount in my_app/views.py as shown below:

# "my_app/views.py"

from django.http import HttpResponse
from app.models import MyModel

def test(request):
    print(MyModel.objects.all()[0].money) # Here
    print(MyModel.objects.all()[0].money.amount) # Here
    return HttpResponse("Test")

Then, these below are displayed on console:

$12.54
12.54

Next, you can convert 12.54 USD to ... EUR.

First, go to Open Exchange Rates, then sign up to get the exchange rates of currencies:

enter image description here

Then, copy App ID from your dashboard:

enter image description here

Then, set OPEN_EXCHANGE_RATES_APP_ID with App ID in core/settings.py:

# "core/settings.py"
                             # Here
OPEN_EXCHANGE_RATES_APP_ID = '368183b0b2644e999ef2a61bd38d0ca3'

Then, run the command below:

python manage.py update_rates

Then, you can convert 12.54 USD to ... EUR with convert_money() and Money() as shown below. *You have to use the value without $ using .amount:

# "my_app/views.py"

from django.http import HttpResponse
from app.models import MyModel
from djmoney.contrib.exchange.models import convert_money
from djmoney.money import Money

def test(request):
    money = MyModel.objects.all()[0].money.amount
    print(convert_money(Money(money, 'USD'), 'EUR')) # Here
    return HttpResponse("Test")

Then, 12.54 USD is converted to 11.70 EUR as shown below:

€11.70

You can see django-money doc which has more details.

And, you can update the exchange rates of currencies every 60 minutes with celery beat code in core/tasks.py and core/settings.py as shown below. *Open Exchange Rates can accept 1000 requests per month in Free Plan:

# "core/tasks.py"

from celery import shared_task
from djmoney import settings
from django.utils.module_loading import import_string

@shared_task
def update_rates(app_id):
    backend = import_string(settings.EXCHANGE_BACKEND)(
        access_key=app_id
    )
    backend.update_rates()
    print("Successfully updated")

*You should put OPEN_EXCHANGE_RATES_APP_ID and import app, crontab and update_rates just before the celery beat code in settings.py as shown below:

# "core/settings.py"

OPEN_EXCHANGE_RATES_APP_ID = '368183b0b2644e999ef2a61bd38d0ca3'

from .celery import app
from celery.schedules import crontab
from .tasks import update_rates

@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    sender.add_periodic_task(
        crontab(minute='*/60'),
        update_rates.s(OPEN_EXCHANGE_RATES_APP_ID),
        name='update_rates'
    )

Leave a comment