SQLAlchemy:在内部格式和数据库格式之间来回转换列值
SQLAlchemy: Convert column value back and forth between internal and database format
在我的数据库中,我有一些列以某种奇怪的格式存储数据。由于数据库也被其他代码使用,我无法更改数据格式。
例如,一种奇怪的格式是将时间值表示为字符串,如 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 对象转换为字符串,然后返回?我知道这会使某些查询变得不可能,例如 between
或 like
或求和等,但没关系。
请记住,时间只是我需要转换数据的例子之一;所以请尽量保持通用的回复。
使用 type decorator 处理与自定义格式之间的转换。在定义列时使用此类型而不是 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))
在我的数据库中,我有一些列以某种奇怪的格式存储数据。由于数据库也被其他代码使用,我无法更改数据格式。
例如,一种奇怪的格式是将时间值表示为字符串,如 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 对象转换为字符串,然后返回?我知道这会使某些查询变得不可能,例如 between
或 like
或求和等,但没关系。
请记住,时间只是我需要转换数据的例子之一;所以请尽量保持通用的回复。
使用 type decorator 处理与自定义格式之间的转换。在定义列时使用此类型而不是 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))