在我的数据库中,我有一些列以某种奇怪的格式存储数据。由于该数据库也被其他代码使用,因此我无法更改数据格式。
例如,一种奇怪的格式是时间值表示为类似于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代码编写转换。)
真的没有办法将两者结合吗?例如,我定义了两个函数,例如python2sql
和sql2python
,哪个SQLAlchemy用于将值从python对象透明地转换为string和back?我知道这将使某些查询成为不可能,例如between
或like
或求和之类,但这没关系。
[请记住,时间只是示例,我需要转换数据;因此请尽量保持回复的通用性。
使用类型修饰符处理与自定义格式之间的转换。定义列时,请使用此类型,而不要使用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))