Skip to main content
 首页 » 编程设计

python之使 SQLAlchemy 映射类分布在不同模块中的惯用方法

2025年05月04日11freeliver54

如何将相关的 SQLAlchemy 映射类分布到不同模块的问题已经出现 quite一个few次here .不过,没有一个提议的解决方案对我很有效,我很想知道如何正确处理(即我不想让我的代码可运行,我想做正确的事)。

我很喜欢this solution :

基础.py
from sqlalchemy.ext.declarative import declarative_base 
Base = declarative_base() 

a.py
from sqlalchemy import * 
from base import Base 
from sqlalchemy.orm import relationship 
 
class A(Base): 
    __tablename__ = "A" 
    id  = Column(Integer, primary_key=True) 
    Bs  = relationship("B", backref="A.id") 
    Cs  = relationship("C", backref="A.id") 

b.py
from sqlalchemy import * 
from base import Base 
 
class B(Base): 
    __tablename__ = "B" 
    id    = Column(Integer, primary_key=True) 
    A_id  = Column(Integer, ForeignKey("A.id")) 

c.py
from sqlalchemy import * 
from base import Base 
 
class C(Base): 
    __tablename__ = "C"     
    id    = Column(Integer, primary_key=True) 
    A_id  = Column(Integer, ForeignKey("A.id")) 

主.py
from sqlalchemy import create_engine 
from sqlalchemy.orm import relationship, backref, sessionmaker 
 
import base 
 
import a 
import b 
import c 
 
engine = create_engine("sqlite:///:memory:") 
base.Base.metadata.create_all(engine, checkfirst=True) 
Session = sessionmaker(bind=engine) 
session = Session() 
 
# snip 

但是,如果我希望能够对 a.py 中的 A 类做一些事情,而不是定义它怎么办?例如

a.py
from sqlalchemy import * 
from base import Base 
from sqlalchemy.orm import relationship 
import main 
 
class A(Base): 
    __tablename__ = "A" 
    id  = Column(Integer, primary_key=True) 
    Bs  = relationship("B", backref="A.id") 
    Cs  = relationship("C", backref="A.id") 
 
def populate_A(session): 
    for i in range(10): 
        new_A = A(id=i) 
        session.add(new_A) 
    session.commit() 
 
if __name__ == '__main__': 
    session = main.Session() 
    populate_A(session) 

这就是我想要构建我的代码的方式 - 从语义上讲,A 和 populate_A 似乎应该位于同一个模块中。但显然这在上面的示例中不起作用,因为循环 a -> main -> a import。

所以我通常会在某处定义 A (a.py),然后在导入 main (a_functions.py ?) 的单独模块中执行操作。或者,由于创建 session 不需要导入映射类但创建表需要,我是否将这两个功能放在不同的模块中?或者我在 main.py 中做了一些粗暴的事情,比如

def create_tables(): 
    import a, b, c 
    engine = create_engine("sqlite:///:memory:") 
    base.metadata.create_all(engine) 

这样 a、b 和 c 仅在我需要创建表时有条件地导入,避免循环导入?

简而言之,使用 SQLAlchemy 的包的惯用高级组织是什么样的?

请您参考如下方法:

我认为这实际上是 Python 习语的问题,而不是 SQLAlchemy 习语的问题。 According to Guido Van Rossum, running scripts within a package is an anti-pattern (zzeek 在评论中暗示了这一点)。所以 a.py、b.py 和 c.py 不应该有 if __name__ == '__main__' block 。