首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在SQLalchemy和SQLite中应该如何处理小数

在SQLalchemy和SQLite中应该如何处理小数
EN

Stack Overflow用户
提问于 2012-04-28 02:12:46
回答 3查看 22.4K关注 0票数 26

当我在SQLite数据库引擎中使用数值列时,SQLalchemy会给我以下警告。

SAWarning:方言sqlite+pysqlite本身不支持十进制对象

我正在尝试找出在SQLalchemy中使用pkgPrice = Column(Numeric(12,2))的最好方法,同时仍然使用SQLite。

这个问题1展示了一种使用sqlite3.register_adapter(D, adapt_decimal)让SQLite接收和返回十进制,但存储字符串的方法,但我还不知道如何深入SQLAlchemy核心来做这件事。类型装饰器看起来是正确的方法,但我还不了解它们。

有没有人有一个SQLAlchemy类型的装饰器配方,可以在SQLAlchemy模型中包含数字或小数,但在SQLite中将它们存储为字符串?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-05-01 00:15:17

代码语言:javascript
复制
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
票数 19
EN

Stack Overflow用户

发布于 2012-04-29 17:49:31

由于看起来您使用小数表示货币值,我建议您做安全的事情,将货币值存储在其最小面值中,例如1610美分而不是16.10美元。然后,您可以只使用Integer列类型。

这可能不是您期望的答案,但它解决了您的问题,并且通常被认为是合理的设计。

票数 18
EN

Stack Overflow用户

发布于 2018-09-27 06:28:21

这里有一个受@van和@JosefAssad启发的解决方案。

代码语言:javascript
复制
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

就像@敬会牛提到的,当小数作为字符串存储在sqlite中时,一些查询并不总是像预期的那样工作,比如session.query(T).filter(T.value > 100),或者像sqlalchemy.sql.expression.func.min,甚至order_by,因为SQL比较字符串(例如字符串中的"9.2“> "19.2”),而不是我们在这些情况下预期的数字值。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10355767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档