给出以下代码片段
t = Table(
"foo",
MetaData(),
Column("bar", DateTime()),
)
engine.execute(t.insert((datetime(1900, 1, 1),)))
engine.execute(t.insert(("1900-01-01",)))
最后一条语句适用于 postgresql,但不适用于 Spark 例如
Cannot safely cast 'bar': string to timestamp
[SQL: INSERT INTO TABLE `foo` VALUES (%(bar)s)]
[parameters: {'bar': '1900-01-01'}]
我可以使用自定义类型来管理它,例如
class MyDateTime(TypeDecorator):
impl = DateTime
def process_bind_param(self, value, dialect):
if dialect.name == "hive" and isinstance(value, str):
return datetime.strptime(value, "%Y-%m-%d")
return value
t = Table(
"foo",
MetaData(),
Column("bar", MyDateTime()),
)
但解决方案
- 当我们直接检查方言名称时,这看起来很hacky
- 我需要为方言自定义现有类型,而不是实现新类型,因为我们有 DateTime 类型的代码库
sqlalchemy 有没有自定义现有类型的解决方案?
最佳答案
没有内置方法可以为特定方言自定义标准 SQLAlchemy 类型(例如 DateTime()
)的参数绑定(bind)处理。不过,您可以使用一些解决方法。
一种解决方法是创建一个自定义类型来包装标准类型并重写 process_bind_param()
方法。例如,以下代码显示了一个自定义类型,该类型重写 process_bind_param()
方法以将字符串转换为 Hive 方言的日期时间对象:
class MyDateTime(TypeDecorator):
impl = DateTime
def process_bind_param(self, value, dialect):
if dialect.name == "hive" and isinstance(value, str):
return datetime.strptime(value, "%Y-%m-%d")
return value
然后,您可以在 SQLAlchemy 架构中使用此自定义类型,而不是标准 DateTime()
类型。例如:
t = Table(
"foo",
MetaData(),
Column("bar", MyDateTime()),
)
另一个解决方法是使用自定义方言来覆盖标准 DateTime()
类型的 bind_param()
方法。例如,以下代码显示了一个自定义方言,该方言重写 bind_param()
方法以将字符串转换为 Hive 方言的日期时间对象:
class MyHiveDialect(postgresql.PGDialect):
def bind_param(self, value, type_):
if type_ == DateTime and isinstance(value, str):
return datetime.strptime(value, "%Y-%m-%d")
return super().bind_param(value, type_)
然后,您可以在创建 SQLAlchemy 引擎时使用此自定义方言。例如:
engine = create_engine("postgresql://localhost/foo", dialect=MyHiveDialect())
您选择哪种解决方法取决于您的具体需求。如果您只需要为单一方言的特定类型自定义参数绑定(bind)处理,那么第一个解决方法可能是最简单的解决方案。如果您需要为多种类型或多种方言自定义参数绑定(bind)处理,那么第二种解决方法可能是更好的解决方案。
请注意,这两种解决方法都被认为是“hacky”解决方案。没有官方方法可以为特定方言的标准 SQLAlchemy 类型自定义参数绑定(bind)处理。如果您需要这样做,那么您应该意识到您的代码可能很脆弱,并且可能无法与 SQLAlchemy 的 future 版本一起使用。
关于python - sqlalchemy:如何为方言自定义标准类型(例如 DateTime() 参数绑定(bind)处理)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77018288/