import re
from django import newforms as forms
class CurrencyField (forms.RegexField):
currencyRe = re.compile(r'^[0-9]{1,5}(.[0-9][0-9])?$')
def __init__(self, *args, **kwargs):
super(CurrencyField, self).__init__(
self.currencyRe, None, None, *args, **kwargs)
def clean(self, value):
value = super(CurrencyField, self).clean(value)
return float(value)
class CurrencyInput (forms.TextInput):
def render(self, name, value, attrs=None):
if value != '':
try:
value = u"%.2f" % value
except TypeError:
pass
return super(CurrencyInput, self).render(name, value, attrs)
class MyForm (forms.Form):
amount = CurrencyField(widget=CurrencyInput, initial=5)
Comments
Looks good, but is Decimal a better choice than float?
#
Yes you could replace line 12 with
but to take advantage of that extra accuracy, you'd need to use IntegerField in the database and do fixed-point conversion when you read and write it.
As it stands above (assuming a FloatField database column) the Decimal will buy you nothing, as the value is returned via float() by django, so you'll run out of accuracy at the same point.
As a general rule, however, it is better to use Decimal than float in python when dealing with currency.
#
May be it would better to use NumPy (it is scientific python extension for very long integer numbers and operations between them)
#
You could reverse the order in which
CurrencyFieldandCurrencyInputare defined, and addto the definition of
CurrencyField.This way there's no need to define the form field's widget class explicitly.
#
Easy internationalization: to handle both dot and comma as a decimal separator, use this regex:
Replace
CurrencyField'sclean()return value withIf you want to display commas instead of dots in forms by default, replace
CurrencyInput'stryclause with#
If you are planning on using
decimalto validate then make sure to account for the two special cases (inf and nan). See django ticket #7777 for details.#
You really really really should't use float for monetary values. In some cases it's even illegal, because float loses precision and with money that's a no-no.
#