首页 > 解决方案 > 已解决:在 volatile 设置中向 ORM SQLAlchemy 表添加新列

问题描述

我正在为 MQTT-Broker https://github.com/volkerjaenisch/amqtt_db开发开源持久层

传入的 MQTT 消息是不规则的数据块,因此通常 DB-Backend 是某种对象存储。

我很难做到这一点,并将 blob 反序列化为类型化的数据列,并将它们存储到一个快速的关系数据库中。我的最终目标是 timescaleDB,但首先我通过 SQLAlchemy 使用一个 API 访问大量数据库。

MQTT 消息是易变的(认为并不总是完整的),因此 DB 方案必须动态调整,例如为新信息添加新列。

First Message:
Time: 1234
Temperature : 23.4

Second Message:
Time: 1245
Temperature : 23.6
Rel Hum : 87 %

我已经使用 SQLalchemy ORM 十多年了,但总是用于相当静态的数据库。所以我是动态工作的新手。

利用 ORM 从传入的 MQTT 消息的结构中动态构建数据库表是非常可行的并且非常完美。

但目前我被 MQTT-Packages 中的附加信息的情况所困扰,这些信息用新列扩展了表。

到目前为止我做了什么:

利用 sqlalchemy-migration 可以很容易地将新列动态添加到数据库中的现有表中。在代码中,“topic_cls”是声明性类,“column_def”是 col_name - 类型映射。

from migrate.versioning.schema import Table as MiTable, Column as MiColumn
    
def add_new_colums(self, topic_cls, column_def):
    table_name = str(topic_cls.__table__.name)
    table = MiTable(table_name, self.metadata)
    for col_name, col_type in column_def.items():
        col = MiColumn(col_name, col_type)
        col.create(table)

奇迹般有效。但是如何让数据库的这些变化反映到声明性类中呢?我试图对桌子进行新的检查:

new_table = Table(topic_cls.__table__.name, self.metadata, autoload_with=self.engine)

这也有效,但它给了我一个新表,但不是一个声明性基础。

所以我的愚蠢问题是:

  1. 这是实现我的目标的正确方法吗?
  2. 如何通过检查数据库中已经存在的表来获得声明性类?

“放弃 ORM 并使用 SQL”不是我要寻找的答案。

干杯,沃尔克

标签: pythonsqlalchemyorm

解决方案


找到了一个解决方案,但它有点像黑客。

new_table = Table("test/topic_growth", Base.metadata, autoload_with=self.engine)

Base.metadata.remove(topic_cls.__table__)

new_dcl = type(str(table_name), (Base,), {'__table__': new_table})

Base.metadata._add_table(table_name, None, new_table)

通过检查获得新表后,从元数据中删除旧表条目。然后使用新表和相同的表名生成一个新的声明性基础。最后将新表添加到元数据中。


推荐阅读