Django: How do I store cash value?

I ran into a paradigm problem. I do not know whether to store money as Decimal (), or if I should store it as a string and convert it to decimal. My reasoning is this:

PayPal requires 2 decimal places , so if I have a product that is $ 49, PayPal wants to see that 49.00 is encountered with the wire. Django DecimalField () does not set the decimal amount. It stores the maximum number of decimal places. So, if you have 49 and you have a field equal to 2 decimal places, it will still save it as 49. I know that Django is basically type casting when it deserializes back from the database to decimal (since Databases do not have decimal fields), therefore, I am not completely concerned about speed problems, as well as the design problems of this problem. I want to do what works best for extensibility.

Or, even better, does anyone know how to configure django DecimalField () to always format the TWO_PLACES formatting style.

+63
python decimal django currency django-models
Jan 6 '10 at
source share
8 answers

You might want to use the .quantize() method. This will round the decimal value to a certain number of places, the argument you specify indicates the number of places:

 >>> from decimal import Decimal >>> Decimal("12.234").quantize(Decimal("0.00")) Decimal("12.23") 

It can also take an argument to indicate which rounding method you want (different accounting systems may require different rounding). More information in Python Docs .

Below is a field that automatically produces the correct value. Please note that this only happens when it is retrieved from the database and will not help you when you install it yourself (until you save it in db and get it again!).

 from django.db import models from decimal import Decimal class CurrencyField(models.DecimalField): __metaclass__ = models.SubfieldBase def to_python(self, value): try: return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01")) except AttributeError: return None 

[edit]

__metaclass__ added, see Django: Why does this custom model field not behave as expected?

+61
Jan 06
source share

I think you should save it in decimal format and format it to format 00.00 only , and then send it to PayPal, for example:

 pricestr = "%01.2f" % price 

If you want, you can add a method to your model:

 def formattedprice(self): return "%01.2f" % self.price 
+18
Jan 6
source share

My late version is a party that adds southern migrations.

 from decimal import Decimal from django.db import models try: from south.modelsinspector import add_introspection_rules except ImportError: SOUTH = False else: SOUTH = True class CurrencyField(models.DecimalField): __metaclass__ = models.SubfieldBase def __init__(self, verbose_name=None, name=None, **kwargs): decimal_places = kwargs.pop('decimal_places', 2) max_digits = kwargs.pop('max_digits', 10) super(CurrencyField, self). __init__( verbose_name=verbose_name, name=name, max_digits=max_digits, decimal_places=decimal_places, **kwargs) def to_python(self, value): try: return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01")) except AttributeError: return None if SOUTH: add_introspection_rules([ ( [CurrencyField], [], { "decimal_places": ["decimal_places", { "default": "2" }], "max_digits": ["max_digits", { "default": "10" }], }, ), ], ['^application\.fields\.CurrencyField']) 
+13
May 09 '13 at
source share

Money should be stored in a cash field, which, unfortunately, does not exist. Since money is a two-dimensional value (amount, currency).

There is a python-money lib that has many forks, but I did not find a working one.




Recommendations:

python-money is probably the best fork https://bitbucket.org/acoobe/python-money

django-money recommended by akumria: http://pypi.python.org/pypi/django-money/ (havent tried another one).

+12
Jul 23 2018-12-23T00:
source share

I suggest avoiding mixing the view with the repository. Store the data as a decimal value with two places.

In the user interface layer, display it in a form suitable for the user (therefore, possibly omit ".00").

When you send data to PayPal, format it as needed.

+10
Jan 06
source share

Based on @Will_Hardy's answer, here you don't need to specify max_digits and decimal_places every time:

 from django.db import models from decimal import Decimal class CurrencyField(models.DecimalField): __metaclass__ = models.SubfieldBase def __init__(self, verbose_name=None, name=None, **kwargs): super(CurrencyField, self). __init__( verbose_name=verbose_name, name=name, max_digits=10, decimal_places=2, **kwargs) def to_python(self, value): try: return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01")) except AttributeError: return None 
+4
Nov 01
source share

In my experience, as well as from others , money is best stored as a combination of currency and the amount in cents.

It is very easy to process and compute with it.

+3
Nov 01 '12 at 11:22
source share

You store it as a DecimalField and manually add decimals if you need, as Valya said, to use the basic formatting methods.

You can even add a model method to your product or transaction model, which spits out DecimalField as an appropriate formatted string.

+1
Jan 6
source share



All Articles