SQLAlchemy:在内部和数据库格式之间来回转换列值

问题描述 投票:9回答:1

在我的数据库中,我有一些列以某种奇怪的格式存储数据。由于该数据库也被其他代码使用,因此我无法更改数据格式。

例如,一种奇怪的格式是时间值表示为类似于23:42:30的字符串。我想拥有一些使我能够始终在python端使用datetime.time对象的魔力。

一个非常简单的解决方案是:

col_raw = Column('col', String(7))

@property
def col(self):
    return datetime.strptime(self.col_raw, '%H:%M:%S').time()
@col.setter
def colself, t):
    self.col_raw = t.strftime('%H:%M:%S')

但是,这仅解决了读取和写入数据的问题。这样的东西是不可能的:

Table.query.filter(Table.col == time(23,42,30))

另一种方法是使用hybrid extension。这样,查询就可以了,但是如果我看正确的话,就不会写。此外,它要求对所有内容编写两次编码,一次使用python代码,一次使用SQL代码。 (另一个问题:我不确定是否只能使用SQL代码编写转换。)

真的没有办法将两者结合吗?例如,我定义了两个函数,例如python2sqlsql2python,哪个SQLAlchemy用于将值从python对象透明地转换为string和back?我知道这将使某些查询成为不可能,例如betweenlike或求和之类,但这没关系。

[请记住,时间只是示例,我需要转换数据;因此请尽量保持回复的通用性。

python orm sqlalchemy data-conversion
1个回答
14
投票

使用类型修饰符处理与自定义格式之间的转换。定义列时,请使用此类型,而不要使用String

class MyTime(TypeDecorator):
    impl = String

    def __init__(self, length=None, format='%H:%M:%S', **kwargs)
        super().__init__(length, **kwargs)
        self.format = format

    def process_literal_param(self, value, dialect):
        # allow passing string or time to column
        if isinstance(value, basestring):  # use str instead on py3
            value = datetime.strptime(value, self.format).time()

        # convert python time to sql string
        return value.strftime(self.format) if value is not None else None

    process_bind_param = process_literal_param

    def process_result_value(self, value, dialect):
        # convert sql string to python time
        return datetime.strptime(value, self.format).time() if value is not None else None

# in your model
class MyModel(Base):
    time = Column(MyTime(length=7))
© www.soinside.com 2019 - 2024. All rights reserved.