1. Waldemar Kornewald
  2. djangoappengine

Commits

Waldemar Kornewald  committed 1f641cc

added support for DecimalField. patch again contributed by bitbucket user "mrk", thanks a lot, this is really cool!

  • Participants
  • Parent commits 1af9c46
  • Branches default

Comments (0)

Files changed (5)

File db/base.py

View file
     NonrelDatabaseOperations, NonrelDatabaseWrapper, NonrelDatabaseClient, \
     NonrelDatabaseValidation, NonrelDatabaseIntrospection
 import logging, os
+from django.db.backends.util import format_number
 
 def auth_func():
     import getpass
 class DatabaseOperations(NonrelDatabaseOperations):
     compiler_module = __name__.rsplit('.', 1)[0] + '.compiler'
 
+    DEFAULT_MAX_DIGITS = 16
+    def value_to_db_decimal(self, value, max_digits, decimal_places):
+        if value is None: 
+            return None
+        sign = value < 0 and u'-' or u''
+        if sign: 
+            value = abs(value)
+        if max_digits is None: 
+            max_digits = self.DEFAULT_MAX_DIGITS
+
+        if decimal_places is None:
+            value = unicode(value)
+        else:
+            value = format_number(value, max_digits, decimal_places)
+        decimal_places = decimal_places or 0
+        n = value.find('.')
+
+        if n < 0:
+            n = len(value)
+        if n < max_digits - decimal_places:
+            value = u"0" * (max_digits - decimal_places - n) + value
+        return sign + value
+
     def sql_flush(self, style, tables, sequences):
         self.connection.flush()
         return []

File db/compiler.py

View file
 from djangotoolbox.db.basecompiler import NonrelQuery, NonrelCompiler, \
     NonrelInsertCompiler, NonrelUpdateCompiler, NonrelDeleteCompiler
 
+import decimal
+
 # Valid query types (a dictionary is used for speedy lookups).
 OPERATORS_MAP = {
     'exact': '=',
 
         # the following GAE database types are all unicode subclasses, cast them
         # to unicode so they appear like pure unicode instances for django
-        if isinstance(value, (Category, Email, Link, PhoneNumber, PostalAddress,
+        if isinstance(value, basestring) and value and db_type.startswith('decimal'):
+            value = decimal.Decimal(value)
+        elif isinstance(value, (Category, Email, Link, PhoneNumber, PostalAddress,
                 Text, unicode)):
             value = unicode(value)
         elif isinstance(value, Blob):
             db_sub_type = db_type.split(':', 1)[1]
             value = [self.convert_value_for_db(db_sub_type, subvalue)
                      for subvalue in value]
+        elif isinstance(value, decimal.Decimal) and db_type.startswith("decimal:"):
+            value = self.connection.ops.value_to_db_decimal(value, *eval(db_type[8:]))
 
         if db_type == 'gae_key':
             return value

File tests/__init__.py

View file
 from .filter import FilterTest
 from .order import OrderTest
 from .not_return_sets import NonReturnSetsTest
+from .decimals import DecimalTest

File tests/decimals.py

View file
+from .testmodels import DecimalModel
+from django.test import TestCase
+
+from decimal import Decimal
+D = Decimal
+
+class DecimalTest(TestCase):
+    
+    DECIMALS =  D("12345.6789"), D("5"), D("345.67"), D("45.6"), D("2345.678"),
+
+    def setUp(self):
+        for d in self.DECIMALS:
+          DecimalModel(decimal=d).save()
+
+    def test_filter(self):
+        d = DecimalModel.objects.get(decimal=D("5.0"))
+
+        self.assertTrue(isinstance(d.decimal, Decimal))
+        self.assertEquals(str(d.decimal), "5.00")
+        
+        d = DecimalModel.objects.get(decimal=D("45.60"))
+        self.assertEquals(str(d.decimal), "45.60")
+        
+        # Filter argument should be converted to Decimal with 2 decimal_places
+        d = DecimalModel.objects.get(decimal="0000345.67333333333333333")
+        self.assertEquals(str(d.decimal), "345.67")
+      
+    def test_order(self):
+        rows = DecimalModel.objects.all().order_by('decimal')
+        values = list(d.decimal for d in rows)
+        self.assertEquals(values, sorted(values))
+        

File tests/testmodels.py

View file
 
     class Meta:
         ordering = ('-priority',)
+
+class DecimalModel(models.Model):
+  decimal = models.DecimalField(max_digits=9, decimal_places=2)