python - 已解决:在 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)
这也有效,但它给了我一个新表,但不是一个声明性基础。
所以我的愚蠢问题是:
- 这是实现我的目标的正确方法吗?
- 如何通过检查数据库中已经存在的表来获得声明性类?
“放弃 ORM 并使用 SQL”不是我要寻找的答案。
干杯,沃尔克
解决方案
找到了一个解决方案,但它有点像黑客。
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)
通过检查获得新表后,从元数据中删除旧表条目。然后使用新表和相同的表名生成一个新的声明性基础。最后将新表添加到元数据中。
推荐阅读
- python - ValueError:matmul 尝试将 sklearn 的线性回归器拟合到 pandas 数据帧实例时
- node.js - 从 S3 读取 ZIP 存档,并将未压缩版本写入新存储桶
- vue.js - 如何从 vue 中的特定 getter 中检索数据?
- python - 带有字典默认值的 typing.NamedTuple
- node.js - 部署“react-admin”应用程序时,Heroku 服务器因“JavaScript 堆内存不足”而崩溃
- c# - 将 C# 对象转换为 IOpenApiAny
- jsf - “主题”必须以 ';' 结尾 分隔符
- iot - 为什么 MQTT 和 CoAP 的有效载荷大小不同?
- flutter - Flutter StatefulWidget 导致多个 HTTP 重新请求
- java - 使用 simpledateformat 解析 6 位毫秒的字符串日期