Django: FloatField or DecimalField for Currency?
Solution 1
Always use DecimalField
for money. Even simple operations (addition, subtraction) are not immune to float rounding issues:
>>> 10.50 - 0.20
10.300000000000001
>>> Decimal('10.50') - Decimal('0.20')
Decimal('10.30')
Solution 2
The answer to the question is correct, however some users will stumble on this question to find out the difference between the DecimalField
and the FloatField
. The float rounding issue Seth brings up is a problem for currency.
The Django Docs States
The
FloatField
class is sometimes mixed up with theDecimalField
class. Although they both represent real numbers, they represent those numbers differently.FloatField
uses Python’sfloat
type internally, whileDecimalField
uses Python’sDecimal
type.
Read more here.
Here are other differences between the two fields:
DecimalField:
- DecimalFields must define a
decimal_places
and amax_digits
attribute. - You get two free form validations included here from the above required attributes, e.g. if you set
max_digits
to4
, and you type in a decimal that is4.00000
(5 digits), you will get this error: Ensure that there are no more than 4 digits in total. - You also get a similar form validation done for decimal places (which in most browsers will also validate on the front end using the step attribute on the input field. If you set
decimal_places = 1
and type in0.001
as the value you will get an error that the minimum value has to be0.1
. - Returns a
decimal.Decimal
, type is<class 'decimal.Decimal'>
- Does not have the extra validation of
DecimalField
- With a
Decimal
type, rounding is also handled for you due to the required attributes that need to be set as described above. So from the shell, if you - In the database (postgresql), the
DecimalField
is saved as anumeric(max_digits, decimal_places)
Type, and Storage is set as "main", from above example the Type isnumeric(4,1)
More on DecimalField from the Django Docs.
FloatField:
- Returns the built in float type,
<type 'float'>
- No smart rounding, and can actually result in rounding issues as described in Seths answer.
- Does not have the extra form validation that you get from
DecimalField
- In the database (postgresql), the
FloatField
is saved as a "double precision" Type, and Storage is set as "plain"
More on FloatField from the Django Docs.
Applies to Both:
- Both fields extend from the
Field
class and can acceptblank
,null
,verbose_name
,name
,primary_key
,max_length
,unique
,db_index
,rel
,default
,editable
,serialize
,unique_for_date
,unique_for_month
,unique_for_year
,choices
,help_text
,db_column
,db_tablespace
,auto_created
,validators
,error_messages
attributes, as all Fields that extend fromField
would have. - The default form widget for both fields is a
TextInput
.
I came across this question when looking for the difference between the two fields so I think this will help those in the same situation :)
UPDATE: To answer the question, I think you can get away with either to represent currency, although Decimal
is a much better fit. There is a rounding issue when it counts to float's so you have to use round(value, 2)
in order to keep your float
representation rounded to two decimal places. Here is a quick example:
>>> round(1.13 * 50 + .01, 2)
56.51
You can still get in trouble with float
and round
. Like here we see it rounds down on a value of 5
:
>>> round(5.685, 2)
5.68
But in this case, it will round up:
>>> round(2.995, 2)
3.0
It has all to do with how the float is stored in memory. See here.
Solution 3
I know this is super old, but I stumbled on it looking for something completely different, and I wanted to throw out there that in general it is inadvisable to use floating point numbers (float or decimal) for currency, as floating point math rounding will invariably lead to small errors in calculation that can add up to very large discrepancies over time.
Instead, use an integer field or a string at your preference. Multiply your currency to move the decimal place to the end and make a whole number when you store it, and then move that decimal place back where it belongs when you need to show it. This is basically how banks (and most currency libraries) handle storing data and will save you loads of trouble later on.
I learned this the hard way because it's not really a common topic; maybe this saves someone else from doing the same thing.
Solution 4
edit: The Satchmo Project is no longer active, so take a look at these alternatives for handling currency
The Django-based Satchmo Project has a CurrencyField and CurrencyWidget that are worth taking a look at.
Check out the satchmo_utils app directory for the source

Hellnar
Updated on June 22, 2021Comments
-
Hellnar over 1 year
I am curious which one would be better fitting as a currency field ? I will do simple operations such as taking difference, the percentage between old and new prices. I plan to keep two digits after the zero (ie 10.50) and majority of the time if these digits are zero, I will be hiding these numbers and display it as "10"
ps: Currency is NOT dollar based :)
-
Rockallite over 8 years
>>> 10.50 - 0.20
in Python 2.7 get10.3
. -
teewuane about 8 yearsWelp, crap. I'll be migrating a lot of data off of my FloatField field/columns to DecimalField...
-
Jesvin Jose about 8 yearsHigh time we have a "dont use floating point for money" analog to bobince's stackoverflow.com/a/1732454/604511
-
Seth over 7 years@Rockallite - try
1.00 + 0.14
, or"%.15f" % (10.5 - 0.2)
- The issue can be obscured due to (I assume) bugs.python.org/issue1580 or something like it. -
Menglong Li over 5 years@teewuane Did you meet any troubles when turning FloatField to DecimalField in your Django project? I'm refactoring some old projects handling money but using Float everywhere, OMG, Thx in advance.
-
teewuane over 5 years@MenglongLi I actually ended up converting everything from floats to integers (not decimals) and only deal with cents. Everything is stored in cents and all calculations are in cents. I then will display the results in US dollars with a simple function that converts
1295
to12.95
. I found that to be the best for my needs. It has a few quirks but ultimately simplified everything for me. -
Seth over 5 yearsPython3's
round()
does "banker's rounding", which should be ok for conversion of currency. The float to Decimal conversion function would be something likelambda floatval: round(Decimal("%.12f" % floatval), 2)
. -
Ankan-Zerob over 3 yearsIt seems like I will always use DecimalField over FloatField. I don't see any benefit/ease of use/simplicity to choose FloatField whilst trading off with the rounding issues.
-
radtek over 3 yearsyeah DecimalField if you are dealing with a finite set of decimal places like with currency. If you want float type, use FloatField (probably a more rare use case).
-
Gathide over 1 yearWith
Decimal('10.30')
, how do you get back to10.30
? -
Seth over 1 year@Gathide if you mean "how do I convert to float", you can say
float(Decimal('10.30'))
, but you might not need to. Decimal will smartly convert itself to float when needed. And, there are a bunch of helper methods on the class that can convert it to various forms, like.as_integer_ratio()
, and a number of computational methods that will return results as Decimals, like.sqrt()
. -
Gathide over 1 year@Seth, Noted. I will check out the helper and computational methods.