The newforms package allows you to simply add new field types to your forms.
This snippet shows the addition of a new type of field, to make sure the user enters sensible currency values (either with no decimal, or two-decimal places), and a custom widget to make sure that the value is displayed correctly when the user sees the form.
The CurrencyInput widget simply tries to display the current value in floating point 2-decimal places format (and gives up if it can't). The CurrencyField makes sure that the input value matches a regular expression, and when it is asked to clean the value it converts it to a float.
The regex here limits the amount to 99,999.99 or less. This is within the bounds of accuracy of python's float value. If you want to use truly huge values for the amount, then you'll face problems with the floating point not being able to represent the values you enter, and so the conversion to floating point in the field will fail. In this case it would be better to use python longs, and used a fixed point interpretation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
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
CurrencyField
andCurrencyInput
are 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
'stry
clause with#
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.
#
Please login first before commenting.