La guía o código que hallarás en este post es la solución más fácil y efectiva que hallamos a tus dudas o problema.
Solución:
Dado que parece que está utilizando decimales para valores de moneda, le sugiero que haga lo seguro y almacene el valor de la moneda en su denominación más baja, por ejemplo, 1610 centavos en lugar de 16,10 dólares. Entonces puede usar un tipo de columna Integer.
Puede que no sea la respuesta que esperaba, pero resuelve su problema y generalmente se considera un diseño sensato.
from decimal import Decimal as D
import sqlalchemy.types as types
class SqliteNumeric(types.TypeDecorator):
impl = types.String
def load_dialect_impl(self, dialect):
return dialect.type_descriptor(types.VARCHAR(100))
def process_bind_param(self, value, dialect):
return str(value)
def process_result_value(self, value, dialect):
return D(value)
# can overwrite the imported type name
# @note: the TypeDecorator does not guarantie the scale and precision.
# you can do this with separate checks
Numeric = SqliteNumeric
class T(Base):
__tablename__ = 't'
id = Column(Integer, primary_key=True, nullable=False, unique=True)
value = Column(Numeric(12, 2), nullable=False)
#value = Column(SqliteNumeric(12, 2), nullable=False)
def __init__(self, value):
self.value = value
Aquí hay una solución inspirada tanto en @van como en @JosefAssad.
class SqliteDecimal(TypeDecorator):
# This TypeDecorator use Sqlalchemy Integer as impl. It converts Decimals
# from Python to Integers which is later stored in Sqlite database.
impl = Integer
def __init__(self, scale):
# It takes a 'scale' parameter, which specifies the number of digits
# to the right of the decimal point of the number in the column.
TypeDecorator.__init__(self)
self.scale = scale
self.multiplier_int = 10 ** self.scale
def process_bind_param(self, value, dialect):
# e.g. value = Column(SqliteDecimal(2)) means a value such as
# Decimal('12.34') will be converted to 1234 in Sqlite
if value is not None:
value = int(Decimal(value) * self.multiplier_int)
return value
def process_result_value(self, value, dialect):
# e.g. Integer 1234 in Sqlite will be converted to Decimal('12.34'),
# when query takes place.
if value is not None:
value = Decimal(value) / self.multiplier_int
return value
Como mencionó @Jinghui Niu, cuando el decimal se almacena como cadenas en sqlite, algunas consultas no siempre funcionarán como se espera, como session.query(T).filter(T.value > 100), o cosas como sqlalchemy.sql. expression.func.min, o incluso order_by, porque SQL compara cadenas (por ejemplo, “9.2” > “19.2” en cadenas) en lugar de valores numéricos como esperábamos en estos casos.
Te mostramos las reseñas y valoraciones de los lectores
Agradecemos que desees añadir valor a nuestra información asistiendo con tu veteranía en las críticas.