How should I handle decimal in SQLalchemy & SQLite

后端 未结 3 1049
慢半拍i
慢半拍i 2020-12-24 07:21

SQLalchemy give me the following warning when I use a Numeric column with an SQLite database engine.

SAWarning: Dialect sqlite+pysqlite does not

3条回答
  •  囚心锁ツ
    2020-12-24 07:58

    Here is a solution inspired by both @van and @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
    

    Like @Jinghui Niu mentioned, when decimal is stored as strings in sqlite, some query won't always function as expected, such as session.query(T).filter(T.value > 100), or things like sqlalchemy.sql.expression.func.min, or even order_by, because SQL compares strings (e.g. "9.2" > "19.2" in strings) instead of numerical values as we expected in these cases.

提交回复
热议问题