SQLAlchemy 部分表无法自动建表:Python 模块加载顺序问题

按教程写好 Python model 后,正常情况下 create_all 能自动映射成数据库表。但有一种情况会出现「部分表能建、部分表建不了」的怪现象——本文记录排查过程和最终解法。

背景

项目里 model 分散在 ssms/beans/*.py,建表逻辑集中在 ssms/utils/db_tool.py

问题现象

例如下面这段 db_tool.py 的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# -*- coding: utf-8 -*-


from contextlib import contextmanager

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from ssms.utils.db_setting import SSMS_DB_Base

SQLALCHEMY_DATABASE_URI = 'sqlite:///db/accounts.db'

engine = create_engine(SQLALCHEMY_DATABASE_URI, echo=True) # Connect to database
# engine = create_engine(SQLALCHEMY_DATABASE_URI) # Connect to database
SSMS_DB_Base.metadata.create_all(engine) # Create models


@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
s = sessionmaker(bind=engine)()
s.expire_on_commit = False
try:
yield s
s.commit()
except:
s.rollback()
raise
finally:
s.close()

执行后发现,有些表可以映射,有些表无法映射,非常奇怪。

原因

最后猜测是 Python 的文件加载顺序导致的。在每个 model 和 db_tool.py 里加了一个 print 打印加载顺序,证实:db_tool.py 之前加载的 model 都能映射,在后面加载的就没法映射了

create_all 执行时,只有已经 import 进内存、注册到 metadata 上的 model 才会被建表。

解决方案

ssms/utils/__init__.py 里全部 import 一遍所有的 model,保证加载 db_tool.py 之前,所有 model 都已就绪,即可全部映射。

亲测好用!

后续补充

update at 2021年4月8日09:41:44

看起来 Flask-Migrate 更加容易和强大。

https://flask-migrate.readthedocs.io/en/latest/

Notice: 正常情况下,这里会有一个基于utteranc.es的留言系统,如果看不到,可能要想想办法才能看到。

Powered by Hexo and Hexo-theme-hiker

Copyright © 2012 - 2026 tiaobug.com All Rights Reserved.

鲁ICP备2024124237号-1