使用SQLite生成空数据库,添加数据提示表不存在错误
我来帮你搞定这个SQLite表不存在的问题!你遇到的核心矛盾——能通过sqlalchemy.inspect看到表对象,但实际数据库里没有表——根源在于表类的导入时机晚于create_all的执行,导致SQLAlchemy的元数据里还没注册这些表的定义。
问题原因分析
看你DBHandler.__init__里的代码顺序:
- 先根据配置创建SQLite引擎,直接调用
meta.BASE.metadata.create_all(engine) - 之后才初始化
self.dbt = DBTable(...)
而DBTable的作用是导入default_DB_map.py里的db_info、db_probe这些表类——这些类继承自BASE,只有当它们被导入后,才会自动注册到BASE.metadata中。
所以当你执行create_all的时候,BASE.metadata是空的,自然不会在SQLite数据库里创建任何表;而MySQL能正常运行,大概率是因为你之前已经手动在MySQL里建好表了,不需要create_all生成。至于sqlalchemy.inspect能看到表对象,是因为后续初始化DBTable时导入了表类,内存里有了表定义,但数据库里并没有同步创建。
解决步骤:调整执行顺序
只需要把「导入表类」的步骤提前到「创建表」之前,让BASE.metadata先拿到所有表的定义,再执行create_all即可。修改后的__init__代码如下:
def __init__(self, db_cfg=None): """Load credentials, DB structure and name of DB map from cfg file, create DB session. Create DBTable object to get table names of DB from cfg file, import table classes and get name of primary keys. Args: - db_cfg (yaml) : contains infos about DB structure and location of DB credentials. Misc: - cred = {"host" : "...", "database" : "...", "user" : "...", "passwd" : "..."} """ ... db_cfg = self.load_cfg(db_cfg) # 第一步:先初始化DBTable,导入所有表类,让它们注册到BASE.metadata中 self.dbt = DBTable(map_file=db_cfg["map"], table_dict=db_cfg["tables"], cr_dict=db_cfg["cross-reference"]) # 第二步:再创建引擎、执行建表、初始化会话 if db_cfg["engine"] == "sqlite": engine = sqlalchemy.create_engine("sqlite:///mySQlite.db") meta.BASE.metadata.create_all(engine) # 此时metadata已经有完整的表定义了 session = sessionmaker(bind=engine) self.session = session() elif db_cfg["engine"] == "mysql+mysqlconnector": cred = self.load_cred(db_cfg["credentials"]) engine = sqlalchemy.create_engine(f"{db_cfg['engine']}://{cred['user']}:{cred['passwd']}@{cred['host']}:3306/{cred['database']}") # 可选:给MySQL也加上create_all,方便自动建表 meta.BASE.metadata.create_all(engine) session = sessionmaker(bind=engine) self.session = session() else: self.log.warning("Unkown engine in DB cfg...")
验证效果
修改后,初始化DBHandler时会先通过DBTable导入所有表类,这些类会自动把结构注册到BASE.metadata中。之后调用create_all,SQLAlchemy就会根据元数据里的定义,在SQLite数据库中创建对应的info、probe表,再执行添加数据的操作就不会报「no such table」错误了。
内容的提问来源于stack exchange,提问作者dieggo111

