user2761723
user2761723

Reputation: 11

Convert a price field in django to be in a specific currency

I have a Product model which has a price field and a currency field. the user can save different products using different currencies. some products are saved in usd, some in gbp, etc'..

class Product(models.Model):
    price = models.DecimalField(
        decimal_places=1, 
        max_digits=4, 
        default=0
    )
    usd = 'USD'
    nis = 'NIS'
    gbp = 'GBP'

    CURRENCY_CHOICES = (
        (usd , 'USD'),
        (nis, 'NIS'),
        (gbp, 'GBP')
    )
    currency = models.CharField(
        max_length=3,
        choices=CURRENCY_CHOICES,
        default=usd,
        blank=True
    )

I want to be able to sort and view all of the products in a single currency. how can i add a field, price_in_usd, which will be set automatically when fields 'price' and 'currency' will be set?

something like this for example:

price_in_usd = convert_price_to_usd()
convert_price_to_usd():
 if currency == GPB:
    return price*1.25
 if currency == NIS:
    return price*0.33



   

Upvotes: 1

Views: 2897

Answers (2)

You better use django-money which can handle money values including the conversion of currencies as shown below. *The code below converts USD to EUR:

# "views.py"

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

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

You can see my answer and django-money doc which explain more about how to convert currencies.

Upvotes: 0

Antoine Pinsard
Antoine Pinsard

Reputation: 34972

You can use the clean() method to handle this kind of behaviors.

class Product(models.Model):

    price = models.DecimalField(decimal_places=1, max_digits=4, default=0)
    currency = models.CharField(
        max_length=3,
        choices=CURRENCY_CHOICES,
        default=usd,
        blank=True
    )
    price_in_usd = models.DecimalField(decimal_places=1, max_digits=4, default=0, editable=False)

    def clean(self):
        if self.price and self.currency:
            self.price_in_usd = convert_price_to_usd(self.price, self.currency)

See Django docs to know exactly when the clean() method will be invoked. According to what you do, you may have to call explicitely full_clean() yourself before calling save(). Also clean() won't be called if you use QuerySet.update() or bulk_create() for instance.

Another way to handle this might be to implement it at SQL level using triggers for instance.


However, if you want the price in USD to be updated (hourly, daily or whatever) to always match the current change rate, you will have to use a cron job to update price_in_usd on a regular basis.

If you don't need to sort the data by price_in_usd on the database level, another solution is to use a property:

class Product(models.Model):

    price = models.DecimalField(decimal_places=1, max_digits=4, default=0)
    currency = models.CharField(
        max_length=3,
        choices=CURRENCY_CHOICES,
        default=usd,
        blank=True
    )

    @property
    def price_in_usd(self):
        return convert_price_to_usd(self.price, self.currency)

Upvotes: 1

Related Questions