mirror of
				https://github.com/django/django.git
				synced 2025-10-30 17:16:10 +00:00 
			
		
		
		
	Fixed #33954 -- Prevented models.DecimalField from accepting NaN, Inf, and -Inf values.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							806e9e2d0d
						
					
				
				
					commit
					b92ffebb0c
				
			| @@ -2,7 +2,6 @@ import collections.abc | |||||||
| import copy | import copy | ||||||
| import datetime | import datetime | ||||||
| import decimal | import decimal | ||||||
| import math |  | ||||||
| import operator | import operator | ||||||
| import uuid | import uuid | ||||||
| import warnings | import warnings | ||||||
| @@ -1703,22 +1702,24 @@ class DecimalField(Field): | |||||||
|     def to_python(self, value): |     def to_python(self, value): | ||||||
|         if value is None: |         if value is None: | ||||||
|             return value |             return value | ||||||
|         if isinstance(value, float): |  | ||||||
|             if math.isnan(value): |  | ||||||
|                 raise exceptions.ValidationError( |  | ||||||
|                     self.error_messages["invalid"], |  | ||||||
|                     code="invalid", |  | ||||||
|                     params={"value": value}, |  | ||||||
|                 ) |  | ||||||
|             return self.context.create_decimal_from_float(value) |  | ||||||
|         try: |         try: | ||||||
|             return decimal.Decimal(value) |             if isinstance(value, float): | ||||||
|  |                 decimal_value = self.context.create_decimal_from_float(value) | ||||||
|  |             else: | ||||||
|  |                 decimal_value = decimal.Decimal(value) | ||||||
|         except (decimal.InvalidOperation, TypeError, ValueError): |         except (decimal.InvalidOperation, TypeError, ValueError): | ||||||
|             raise exceptions.ValidationError( |             raise exceptions.ValidationError( | ||||||
|                 self.error_messages["invalid"], |                 self.error_messages["invalid"], | ||||||
|                 code="invalid", |                 code="invalid", | ||||||
|                 params={"value": value}, |                 params={"value": value}, | ||||||
|             ) |             ) | ||||||
|  |         if not decimal_value.is_finite(): | ||||||
|  |             raise exceptions.ValidationError( | ||||||
|  |                 self.error_messages["invalid"], | ||||||
|  |                 code="invalid", | ||||||
|  |                 params={"value": value}, | ||||||
|  |             ) | ||||||
|  |         return decimal_value | ||||||
|  |  | ||||||
|     def get_db_prep_save(self, value, connection): |     def get_db_prep_save(self, value, connection): | ||||||
|         return connection.ops.adapt_decimalfield_value( |         return connection.ops.adapt_decimalfield_value( | ||||||
|   | |||||||
| @@ -67,10 +67,19 @@ class DecimalFieldTests(TestCase): | |||||||
|  |  | ||||||
|     def test_save_nan_invalid(self): |     def test_save_nan_invalid(self): | ||||||
|         msg = "“nan” value must be a decimal number." |         msg = "“nan” value must be a decimal number." | ||||||
|         with self.assertRaisesMessage(ValidationError, msg): |         for value in [float("nan"), math.nan, "nan"]: | ||||||
|             BigD.objects.create(d=float("nan")) |             with self.subTest(value), self.assertRaisesMessage(ValidationError, msg): | ||||||
|         with self.assertRaisesMessage(ValidationError, msg): |                 BigD.objects.create(d=value) | ||||||
|             BigD.objects.create(d=math.nan) |  | ||||||
|  |     def test_save_inf_invalid(self): | ||||||
|  |         msg = "“inf” value must be a decimal number." | ||||||
|  |         for value in [float("inf"), math.inf, "inf"]: | ||||||
|  |             with self.subTest(value), self.assertRaisesMessage(ValidationError, msg): | ||||||
|  |                 BigD.objects.create(d=value) | ||||||
|  |         msg = "“-inf” value must be a decimal number." | ||||||
|  |         for value in [float("-inf"), -math.inf, "-inf"]: | ||||||
|  |             with self.subTest(value), self.assertRaisesMessage(ValidationError, msg): | ||||||
|  |                 BigD.objects.create(d=value) | ||||||
|  |  | ||||||
|     def test_fetch_from_db_without_float_rounding(self): |     def test_fetch_from_db_without_float_rounding(self): | ||||||
|         big_decimal = BigD.objects.create(d=Decimal(".100000000000000000000000000005")) |         big_decimal = BigD.objects.create(d=Decimal(".100000000000000000000000000005")) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user