Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #11206 -- Ensure that the floatformat template filter doesn't s…

…witch to scientific notation when asked to format a zero value with more than six decimal places. Thanks Tai Lee for the report and fix and Facundo Batista for his help when Decimal module expertise was needed.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15736 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 3ecf628b3650e0f9f086b1ae77b43ad5df48a92e 1 parent 9428c23
Ramiro Morales authored March 03, 2011
14  django/template/defaultfilters.py
@@ -149,9 +149,19 @@ def floatformat(text, arg=-1):
149 149
     if p == 0:
150 150
         exp = Decimal(1)
151 151
     else:
152  
-        exp = Decimal('1.0') / (Decimal(10) ** abs(p))
  152
+        exp = Decimal(u'1.0') / (Decimal(10) ** abs(p))
153 153
     try:
154  
-        return mark_safe(formats.number_format(u'%s' % str(d.quantize(exp, ROUND_HALF_UP)), abs(p)))
  154
+        # Avoid conversion to scientific notation by accessing `sign`, `digits`
  155
+        # and `exponent` from `Decimal.as_tuple()` directly.
  156
+        sign, digits, exponent = d.quantize(exp, ROUND_HALF_UP).as_tuple()
  157
+        digits = [unicode(digit) for digit in reversed(digits)]
  158
+        while len(digits) <= abs(exponent):
  159
+            digits.append(u'0')
  160
+        digits.insert(-exponent, u'.')
  161
+        if sign:
  162
+            digits.append(u'-')
  163
+        number = u''.join(reversed(digits))
  164
+        return mark_safe(formats.number_format(number, abs(p)))
155 165
     except InvalidOperation:
156 166
         return input_val
157 167
 floatformat.is_safe = True
16  tests/regressiontests/defaultfilters/tests.py
... ...
@@ -1,6 +1,6 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 import datetime
3  
-import unittest
  3
+from django.utils import unittest
4 4
 
5 5
 from django.template.defaultfilters import *
6 6
 
@@ -29,6 +29,13 @@ def test_floatformat(self):
29 29
         self.assertEqual(floatformat(u'¿Cómo esta usted?'), u'')
30 30
         self.assertEqual(floatformat(None), u'')
31 31
 
  32
+        # Check that we're not converting to scientific notation.
  33
+        self.assertEqual(floatformat(0, 6), u'0.000000')
  34
+        self.assertEqual(floatformat(0, 7), u'0.0000000')
  35
+        self.assertEqual(floatformat(0, 10), u'0.0000000000')
  36
+        self.assertEqual(floatformat(0.000000000000000000015, 20),
  37
+                                     u'0.00000000000000000002')
  38
+
32 39
         pos_inf = float(1e30000)
33 40
         self.assertEqual(floatformat(pos_inf), unicode(pos_inf))
34 41
 
@@ -46,6 +53,13 @@ def __float__(self):
46 53
 
47 54
         self.assertEqual(floatformat(FloatWrapper(11.000001), -2), u'11.00')
48 55
 
  56
+    # This fails because of Python's float handling. Floats with many zeroes
  57
+    # after the decimal point should be passed in as another type such as
  58
+    # unicode or Decimal.
  59
+    @unittest.expectedFailure
  60
+    def test_floatformat_fail(self):
  61
+        self.assertEqual(floatformat(1.00000000000000015, 16), u'1.0000000000000002')
  62
+
49 63
     def test_addslashes(self):
50 64
         self.assertEqual(addslashes(u'"double quotes" and \'single quotes\''),
51 65
                           u'\\"double quotes\\" and \\\'single quotes\\\'')

0 notes on commit 3ecf628

Please sign in to comment.
Something went wrong with that request. Please try again.