Ticket #2365: DecimalField-FloatField.diff
File DecimalField-FloatField.diff, 17.1 KB (added by , 18 years ago) |
---|
-
django/db/models/fields/__init__.py
617 617 def get_manipulator_field_objs(self): 618 618 return [curry(forms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)] 619 619 620 class FloatField(Field):620 class DecimalField(Field): 621 621 empty_strings_allowed = False 622 622 def __init__(self, verbose_name=None, name=None, max_digits=None, decimal_places=None, **kwargs): 623 623 self.max_digits, self.decimal_places = max_digits, decimal_places 624 624 Field.__init__(self, verbose_name, name, **kwargs) 625 625 626 def to_python(self, value): 627 try: 628 import decimal 629 try: 630 return decimal.Decimal(value) 631 except (decimal.InvalidOperation): 632 raise validators.ValidationError, gettext("This value must be a decimal number.") 633 except ImportError: 634 return str(value) 635 636 def _format(self, value): 637 if isinstance(value, basestring): 638 return value 639 else: 640 return self.format_number(value) 641 642 def format_number(self, value): 643 """Formats a number into a string with the requisite number of digits and decimal places.""" 644 645 num_chars = self.max_digits 646 # Allow for a decimal point 647 if self.decimal_places > 0: 648 num_chars += 1 649 # Allow for a minus sign 650 if value < 0: 651 num_chars += 1 652 653 return "%.*f" % (self.decimal_places, value) 654 655 def get_db_prep_save(self, value): 656 value = self._format(value) 657 658 return super(DecimalField, self).get_db_prep_save(value) 659 660 def get_db_prep_lookup(self, lookup_type, value): 661 if lookup_type == 'range': 662 value = [self._format(v) for v in value] 663 else: 664 value = self._format(value) 665 return super(DecimalField, self).get_db_prep_lookup(lookup_type, value) 666 626 667 def get_manipulator_field_objs(self): 627 return [curry(forms.FloatField, max_digits=self.max_digits, decimal_places=self.decimal_places)] 668 # TODO change this (because forms.FloatField returns a float) 669 return [curry(forms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)] 628 670 671 class FloatField(Field): 672 empty_strings_allowed = False 673 def __init__(self, verbose_name=None, name=None, **kwargs): 674 Field.__init__(self, verbose_name, name, **kwargs) 675 676 def get_manipulator_field_objs(self): 677 return [forms.FloatField] 678 629 679 class ImageField(FileField): 630 680 def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs): 631 681 self.width_field, self.height_field = width_field, height_field -
django/db/backends/sqlite3/creation.py
8 8 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', 9 9 'DateField': 'date', 10 10 'DateTimeField': 'datetime', 11 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 11 12 'FileField': 'varchar(100)', 12 13 'FilePathField': 'varchar(100)', 13 'FloatField': 'numeric (%(max_digits)s, %(decimal_places)s)',14 'FloatField': 'numeric', 14 15 'ImageField': 'varchar(100)', 15 16 'IntegerField': 'integer', 16 17 'IPAddressField': 'char(15)', -
django/db/backends/mysql/base.py
22 22 FIELD_TYPE.DATETIME: util.typecast_timestamp, 23 23 FIELD_TYPE.DATE: util.typecast_date, 24 24 FIELD_TYPE.TIME: util.typecast_time, 25 FIELD_TYPE.DECIMAL: None, 26 FIELD_TYPE.NEWDECIMAL: None 25 27 }) 26 28 29 27 30 # This is an extra debug layer over MySQL queries, to display warnings. 28 31 # It's only used when DEBUG=True. 29 32 class MysqlDebugWrapper: -
django/db/backends/mysql/introspection.py
75 75 DATA_TYPES_REVERSE = { 76 76 FIELD_TYPE.BLOB: 'TextField', 77 77 FIELD_TYPE.CHAR: 'CharField', 78 FIELD_TYPE.DECIMAL: 'FloatField', 78 FIELD_TYPE.DECIMAL: 'DecimalField', 79 FIELD_TYPE.NEWDECIMAL: 'DecimalField', 79 80 FIELD_TYPE.DATE: 'DateField', 80 81 FIELD_TYPE.DATETIME: 'DateTimeField', 81 82 FIELD_TYPE.DOUBLE: 'FloatField', -
django/db/backends/mysql/creation.py
9 9 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', 10 10 'DateField': 'date', 11 11 'DateTimeField': 'datetime', 12 'DecimalField': 'decimal(%(max_digits)s, %(decimal_places)s)', 12 13 'FileField': 'varchar(100)', 13 14 'FilePathField': 'varchar(100)', 14 'FloatField': ' numeric(%(max_digits)s, %(decimal_places)s)',15 'FloatField': 'double', 15 16 'ImageField': 'varchar(100)', 16 17 'IntegerField': 'integer', 17 18 'IPAddressField': 'char(15)', -
django/forms/__init__.py
739 739 raise validators.CriticalValidationError, gettext("Enter a whole number between 0 and 32,767.") 740 740 741 741 class FloatField(TextField): 742 def __init__(self, field_name, is_required=False, validator_list=None): 743 if validator_list is None: validator_list = [] 744 validator_list = [validators.isValidFloat] + validator_list 745 TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list) 746 747 def html2python(data): 748 if data == '' or data is None: 749 return None 750 return float(data) 751 html2python = staticmethod(html2python) 752 753 class DecimalField(TextField): 742 754 def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None): 743 755 if validator_list is None: validator_list = [] 744 756 self.max_digits, self.decimal_places = max_digits, decimal_places 745 validator_list = [self.isValidFloat] + validator_list 746 TextField.__init__(self, field_name, max_digits+1, max_digits+1, is_required, validator_list) 757 validator_list = [self.isValidDecimal] + validator_list 758 # Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point. 759 super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list) 747 760 748 def isValid Float(self, field_data, all_data):749 v = validators.IsValid Float(self.max_digits, self.decimal_places)761 def isValidDecimal(self, field_data, all_data): 762 v = validators.IsValidDecimal(self.max_digits, self.decimal_places) 750 763 try: 751 764 v(field_data, all_data) 752 765 except validators.ValidationError, e: … … 755 768 def html2python(data): 756 769 if data == '' or data is None: 757 770 return None 758 return float(data) 771 try: 772 import decimal 773 try: 774 return decimal.Decimal(data) 775 except decimal.InvalidOperation, e: 776 raise ValueError, e 777 except ImportError: 778 return str(data) 759 779 html2python = staticmethod(html2python) 760 780 761 781 #################### -
django/core/validators.py
24 24 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 25 25 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string 26 26 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 27 decimal_re = re.compile(r'^-?(?P<digits>\d+)(\.(?P<decimals>\d+))?$') 27 28 integer_re = re.compile(r'^-?\d+$') 28 29 ip4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$') 29 30 phone_re = re.compile(r'^[A-PR-Y0-9]{3}-[A-PR-Y0-9]{3}-[A-PR-Y0-9]{4}$', re.IGNORECASE) … … 342 343 if val != int(val): 343 344 raise ValidationError, gettext("This value must be a power of %s.") % self.power_of 344 345 345 class IsValid Float(object):346 class IsValidDecimal(object): 346 347 def __init__(self, max_digits, decimal_places): 347 348 self.max_digits, self.decimal_places = max_digits, decimal_places 348 349 349 350 def __call__(self, field_data, all_data): 350 data = str(field_data) 351 try: 352 float(data) 353 except ValueError: 351 match = decimal_re.search(str(field_data)) 352 if not match: 354 353 raise ValidationError, gettext("Please enter a valid decimal number.") 355 if len(data) > (self.max_digits + 1): 354 355 digits = len(match.group('digits') or '') 356 decimals = len(match.group('decimals') or '') 357 358 if digits + decimals > self.max_digits: 356 359 raise ValidationError, ngettext("Please enter a valid decimal number with at most %s total digit.", 357 360 "Please enter a valid decimal number with at most %s total digits.", self.max_digits) % self.max_digits 358 if (not '.' in data and len(data) > (self.max_digits - self.decimal_places)) or ('.' in data and len(data) > (self.max_digits - (self.decimal_places - len(data.split('.')[1])) + 1)):361 if digits > (self.max_digits - self.decimal_places): 359 362 raise ValidationError, ngettext( "Please enter a valid decimal number with a whole part of at most %s digit.", 360 363 "Please enter a valid decimal number with a whole part of at most %s digits.", str(self.max_digits-self.decimal_places)) % str(self.max_digits-self.decimal_places) 361 if '.' in data and len(data.split('.')[1])> self.decimal_places:364 if decimals > self.decimal_places: 362 365 raise ValidationError, ngettext("Please enter a valid decimal number with at most %s decimal place.", 363 366 "Please enter a valid decimal number with at most %s decimal places.", self.decimal_places) % self.decimal_places 364 367 368 def isValidFloat(field_data, all_data): 369 data = str(field_data) 370 try: 371 float(data) 372 except ValueError: 373 raise ValidationError, gettext("Please enter a valid floating point number.") 374 365 375 class HasAllowableSize(object): 366 376 """ 367 377 Checks that the file-upload field data is a certain size. min_size and -
django/core/management.py
756 756 if field_type == 'CharField' and row[3]: 757 757 extra_params['maxlength'] = row[3] 758 758 759 if field_type == ' FloatField':759 if field_type == 'DecimalField': 760 760 extra_params['max_digits'] = row[4] 761 761 extra_params['decimal_places'] = row[5] 762 762 … … 830 830 e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name) 831 831 if isinstance(f, models.CharField) and f.maxlength in (None, 0): 832 832 e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name) 833 if isinstance(f, models. FloatField):833 if isinstance(f, models.DecimalField): 834 834 if f.decimal_places is None: 835 e.add(opts, '"%s": FloatFields require a "decimal_places" attribute.' % f.name)835 e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name) 836 836 if f.max_digits is None: 837 e.add(opts, '"%s": FloatFields require a "max_digits" attribute.' % f.name)837 e.add(opts, '"%s": DecimalFields require a "max_digits" attribute.' % f.name) 838 838 if isinstance(f, models.FileField) and not f.upload_to: 839 839 e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name) 840 840 if isinstance(f, models.ImageField): -
django/contrib/admin/templatetags/admin_list.py
149 149 elif isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField): 150 150 BOOLEAN_MAPPING = {True: 'yes', False: 'no', None: 'unknown'} 151 151 result_repr = '<img src="%simg/admin/icon-%s.gif" alt="%s" />' % (settings.ADMIN_MEDIA_PREFIX, BOOLEAN_MAPPING[field_val], field_val) 152 # FloatFields are special: Zero-pad the decimals.153 elif isinstance(f, models. FloatField):152 # DecimalFields are special: Zero-pad the decimals. 153 elif isinstance(f, models.DecimalField): 154 154 if field_val is not None: 155 155 result_repr = ('%%.%sf' % f.decimal_places) % field_val 156 156 else: -
django/contrib/admin/views/doc.py
294 294 'CommaSeparatedIntegerField': _('Comma-separated integers'), 295 295 'DateField' : _('Date (without time)'), 296 296 'DateTimeField' : _('Date (with time)'), 297 'DecimalField' : _('Decimal number'), 297 298 'EmailField' : _('E-mail address'), 298 299 'FileField' : _('File path'), 299 300 'FilePathField' : _('File path'), 300 'FloatField' : _(' Decimalnumber'),301 'FloatField' : _('Floating point number'), 301 302 'ForeignKey' : _('Integer'), 302 303 'ImageField' : _('File path'), 303 304 'IntegerField' : _('Integer'), -
tests/modeltests/invalid_models/models.py
8 8 9 9 class FieldErrors(models.Model): 10 10 charfield = models.CharField() 11 floatfield = models.FloatField()11 decimalfield = models.DecimalField() 12 12 filefield = models.FileField() 13 13 prepopulate = models.CharField(maxlength=10, prepopulate_from='bad') 14 14 choices = models.CharField(maxlength=10, choices='bad') … … 79 79 80 80 81 81 error_log = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. 82 invalid_models.fielderrors: " floatfield": FloatFields require a "decimal_places" attribute.83 invalid_models.fielderrors: " floatfield": FloatFields require a "max_digits" attribute.82 invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute. 83 invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute. 84 84 invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute. 85 85 invalid_models.fielderrors: "prepopulate": prepopulate_from should be a list or tuple. 86 86 invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list). -
docs/forms.txt
503 503 * isNotEmpty 504 504 * isOnlyDigits 505 505 * isNotOnlyDigits 506 * isInteger 506 * isInteger 507 507 * isOnlyLetters 508 508 * isValidANSIDate 509 509 * isValidANSITime 510 510 * isValidEmail 511 * isValidFloat 511 512 * isValidImage 512 513 * isValidImageURL 513 514 * isValidPhone … … 588 589 Takes an integer argument and when called as a validator, checks that the 589 590 field being validated is a power of the integer. 590 591 591 ``IsValid Float``592 ``IsValidDecimal`` 592 593 Takes a maximum number of digits and number of decimal places (in that 593 order) and validates whether the field is a float with lessthan the594 maximum number of digits and decimal place .594 order) and validates whether the field is a decimal with no more than the 595 maximum number of digits and decimal places. 595 596 597 ``IsValidFloat`` 598 Takes a string argument and validates whether it can be converted to a 599 float. 600 596 601 ``MatchesRegularExpression`` 597 602 Takes a regular expression (a string) as a parameter and validates the 598 603 field value against it.