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

Mar*_*ian 9 python orm sqlalchemy data-conversion

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

例如,一种奇怪的格式是时间值表示为字符串23:42:30.我想有一些魔法可以让我总是datetime.time在python端使用对象.

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

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')
Run Code Online (Sandbox Code Playgroud)

但是,这只能解决读写数据的问题.像这样的东西是不可能的:

Table.query.filter(Table.col == time(23,42,30))
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用混合扩展.这样,查询就有可能,但如果我看得正确,写不会.此外,它需要编写两次编码,一次是在python代码中,一次是在SQL代码中.(其他问题:我不确定转换是否只能使用SQL代码编写.)

真的没有办法将两者结合起来吗?比如我定义了两个功能,比方说python2sqlsql2python,这SQLAlchemy的使用从Python对象的值转换透明地向字符串和后面?我知道,这会使一些查询不可能的,比如betweenlike或款项之类的,不过没关系.

请记住,时间只是我需要转换数据的情况之一; 所以请尽量保持回复的通用性.

dav*_*ism 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))
Run Code Online (Sandbox Code Playgroud)