-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Edge case DecimalField serialization #9135
-
Hey, i've noticed a strange behavior in Decimal serialization
In theory i shouldn't expect any error here. Especially that this code fired after running for few months on production - only when serialized value is greater or equal to 1.0
Same bug occurs for serializers.DecimalField(decimal_places=3, max_digits=4)
configuration - when value is greater or equal to 10
In theory this isn't a problem when someone serializes verified data from psql, this time I serialize raw python objects to json payload and decimals should be rounded up somehow?
Possible solution could be to just cut decimal part that can't fit into the configured places
In [51]: class TestDecimal(serializers.Serializer):
...: something = serializers.DecimalField(decimal_places=4, max_digits=4)
...:
In [52]: TestDecimal({"something": "0.100123"}).data # i know that there should be an object - added dict only to shorten the code
Out[52]: {'something': '0.1001'}
In [53]: TestDecimal({"something": "1.000"}).data
---------------------------------------------------------------------------
InvalidOperation Traceback (most recent call last)
Cell In[53], line 1
----> 1 TestDecimal({"something": "1.000"}).data
File /usr/local/lib/python3.10/site-packages/rest_framework/serializers.py:555, in Serializer.data(self)
553 @property
554 def data(self):
--> 555 ret = super().data
556 return ReturnDict(ret, serializer=self)
File /usr/local/lib/python3.10/site-packages/rest_framework/serializers.py:253, in BaseSerializer.data(self)
251 if not hasattr(self, '_data'):
252 if self.instance is not None and not getattr(self, '_errors', None):
--> 253 self._data = self.to_representation(self.instance)
254 elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
255 self._data = self.to_representation(self.validated_data)
File /usr/local/lib/python3.10/site-packages/rest_framework/serializers.py:522, in Serializer.to_representation(self, instance)
520 ret[field.field_name] = None
521 else:
--> 522 ret[field.field_name] = field.to_representation(attribute)
524 return ret
File /usr/local/lib/python3.10/site-packages/rest_framework/fields.py:1081, in DecimalField.to_representation(self, value)
1078 if not isinstance(value, decimal.Decimal):
1079 value = decimal.Decimal(str(value).strip())
-> 1081 quantized = self.quantize(value)
1083 if not coerce_to_string:
1084 return quantized
File /usr/local/lib/python3.10/site-packages/rest_framework/fields.py:1100, in DecimalField.quantize(self, value)
1098 if self.max_digits is not None:
1099 context.prec = self.max_digits
-> 1100 return value.quantize(
1101 decimal.Decimal('.1') ** self.decimal_places,
1102 rounding=self.rounding,
1103 context=context
1104 )
InvalidOperation: [<class 'decimal.InvalidOperation'>]
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 1 comment 1 reply
-
Facing same issue
Beta Was this translation helpful? Give feedback.
All reactions
-
Problem was size of number with decimals trimmed was > max_digits
in serializer. Resolved by increasing max_digits
Beta Was this translation helpful? Give feedback.