如何将SQLAlchemy声明式模型拆分为模块?

时间:2018-06-29 16:46:56

标签: python sqlalchemy

我需要定义多个包含SQLAlchemy声明性类的模块。我在名为subclass_base()的每个模块中编写了一个函数,实例化后将declarative_base()的基本实例传递到其中。第一个模块的subclass_base()调用正确地将Base实例子类化,并且可以从函数外部看到这些子类。第二个模块的调用没有错误地结束,但是从子函数内部和外部来看,所有子类仅在某些时间反映在Base.__subclasses__中。这是一个最小的工作示例,每个模块中只有一个类定义:

modela.py

from sqlalchemy import Column, Integer, String
def subclass_base(Base):
    class Roles(Base):
        __tablename__ = 'roles'

        id = Column(Integer, primary_key=True)
        name = Column(String(32))

modelb.py

from sqlalchemy import Column, Integer, String
def subclass_base(Base):
    class Locations(Base):
         __tablename__ = 'locations'

        id = Column(Integer, primary_key=True)
        name = Column(String(64))

test.py

from sqlalchemy.ext.declarative import declarative_base
from modela import subclass_base as amod
from modelb import subclass_base as bmod

def test():
    count = 0
    while True:
        try:
            Base = declarative_base()

            amod(Base)

            bmod(Base)
            sc = [subclass.__name__ for subclass in Base.__subclasses__()]
            assert(len(sc) == 2)

            print('.', end='')
            count += 1
        except AssertionError:
            print("Failed after {} successful pass(es)".format(count))
            count = 0

我怀疑这个问题是我忽略了与declarative_base()一起进行的元类工作的特定问题,但是我似乎无法弄清楚发生了什么。我也想知道这是否是继承问题。除了使用函数子类化单个基类之外,我应该采用其他架构方法吗?

1 个答案:

答案 0 :(得分:0)

不要在函数内部定义类。只需在单个定义模块中定义Base,然后从其他模块导入该模块:

db.py

from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()
Session = sessionmaker()

def bind_engine(engine):
    Base.metadata.bind = engine
    Session.configure(bind=engine)

modela.py

from sqlalchemy import Column, Integer, String
from db import Base

class Roles(Base):
    __tablename__ = 'roles'

    id = Column(Integer, primary_key=True)
    name = Column(String(32))

modelb.py

from sqlalchemy import Column, Integer, String
from db import Base

class Locations(Base):
    __tablename__ = 'locations'

    id = Column(Integer, primary_key=True)
    name = Column(String(64))

user_script.py

 from sqlalchemy import create_engine
 engine = create_engine('postgresql://user:pwd@server/database')
 from yourproject.db import bind_engine
 bind_engine(engine)