Open mscansian opened 6 years ago
From these docs you could create a custom attribute that uses a decimal.Context
to translate between a decimal.Decimal
instance and a string.
I haven't tested this, and it's based on how I implemented the same in bloop, but I'm pretty sure it will do what you want. Note the round trip through create_decimal
is required in serialize
to ensure the value meets your context's requirements.
import decimal
from pynamodb.attributes import Attribute
from pynamodb.constants import NUMBER
DYNAMODB_CONTEXT = decimal.Context(
Emin=-128, Emax=126, rounding=None, prec=38,
traps=[
decimal.Clamped, decimal.Overflow, decimal.Inexact,
decimal.Rounded, decimal.Underflow
]
)
class DecimalAttribute(Attribute):
"""
Serialize and deserialize decimal.Decimal instances with a given decimal.Context.
The default decimal.Context comes from the definition used by boto3.
"""
def __init__(self, context=None):
context = context or DYNAMODB_CONTEXT
self.context = context
def serialize(self, value):
# decimal.Decimal -> str
return str(self.context.create_decimal(value))
def deserialize(self, value):
# str -> decimal.Decimal
return self.context.create_decimal(value)
@numberoverzero Thanks for the explanation. Haven't tested it yet, but it looks like it's gonna work. I just think that is also necessary to include attr_type = NUMBER
in the class to avoid DynamoDB saving data as a string (though I'm not sure).
Anyway, don't you guys think this is an attribute worth of a place in the lib itself? I will gladly send a PR if that's the case.
good call! i imported and forgot to add the line.
The maintainers told me they'd rather keep only the primitive attributes in pynamodb.attributes
, which is why I created pynamodb-attributes to complement it.
@numberoverzero I was use your code but I had something problems but I was solve it, the next way:
class DecimalAttribute(Attribute):
attr_type = NUMBER
def __init__(self, context=None, **kwargs):
super().__init__(**kwargs)
context = context or DYNAMODB_CONTEXT
self.context = context
def serialize(self, value):
# decimal.Decimal -> str
return str(self.context.create_decimal(str(value)))
def deserialize(self, value):
# str -> decimal.Decimal
return self.context.create_decimal(value)
I hope that this code help someone
Is there a way to use
decimal.Decimal
in PynamoDB? To my knowledge, the only way to save using theNumberAttribute
is by converting it to float first. I tried sending aDecimal
to theNumberAttribute
, but since it uses JSON as a serializer, it does not work.I'm working with financial data where precision is mandatory and float is not an option for me. Am I missing something or Decimal support is not yet implemented?