在我的项目中,正在使用具有延迟反射的delaretive base。
from sqlalchemy import (
create_engine, Table, Column, Integer, BigInteger, Text, DateTime, Numeric, String,
)
from sqlalchemy.dialects.postgresql import CIDR
from sqlalchemy.orm import mapper, sessionmaker, relationship, backref
from sqlalchemy.orm.mapper import configure_mappers
from sqlalchemy.orm.util import _is_mapped_class
from sqlalchemy.pool import NullPool, QueuePool
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.schema import Sequence
from sqlalchemy.ext.hybrid import hybrid_property
# this class is taken from sqlalchemy recipes
class DeclarativeReflectedBase(object):
_mapper_args = []
@classmethod
def __mapper_cls__(cls, *args, **kw):
cls._mapper_args.append((args, kw))
@classmethod
def prepare(cls, engine):
while cls._mapper_args:
args, kw = cls._mapper_args.pop()
klass = args[0]
if args[1] is not None:
table = args[1]
Table(table.name,
cls.metadata,
extend_existing=True,
autoload_replace=False,
autoload=True,
autoload_with=engine,
schema=table.schema)
for c in klass.__bases__:
if _is_mapped_class(c):
kw['inherits'] = c
break
klass.__mapper__ = mapper(*args, **kw)
Base = declarative_base()
class Reflected(DeclarativeReflectedBase, Base):
__abstract__ = True
class Customer(Reflected):
@declared_attr
def __tablename__(cls):
return "customer"
__table_args__ = {"schema": "schema_customer"}
id = Column('id', Integer, primary_key=True)
balances = relationship(lambda: Balance, backref="customer")
class Balance(Reflected):
@declared_attr
def __tablename__(cls):
return "balance"
__table_args__ = {"schema": "billing"}
id = Column('id', Integer, primary_key=True)
currency = relationship(lambda: Currency)
@hybrid_property
def name_with_currency(self):
return "{0} ({1})".format(self.name, self.currency.name_short)
@name_with_curr.expression
def name_with_curr_expr(cls):
return cls.name + " (" + Currency.name_short + ")"
.......
# and other classes below
def orm_initialization(engine):
Reflected.prepare(engine) # reflect DB tables metadata
S = sessionmaker()
s = S(bind=engine)
try:
contetxs_count = s.query(Contexts).count()
# other classes difine for not constant number of postgresql database contexts
....
# call prepare again
Reflected.prepare(engine)
finally:
s.close()
def sessionmaker_get(host, port, dbname, user, password, existing_engine=None, pooling=False):
if existing_engine is None:
engine = create_engine(
"{dialect}://{user}:{password}@{host}:{port}/{dbname}"
.format(dialect="postgresql", **locals()),
poolclass=NullPool,
echo=False
)
else:
engine = existing_engine
orm_initialization(engine)
S = sessionmaker(bind=engine)
return S
这可行,但ORM的初始化大约需要7-8秒。所以,我想在一些文件中缓存pickled元数据并在创建新的sessionmaker时加载它。我将元数据存储到HDD上的文件中,并尝试在首次调用prepare()之前将此元数据连接到Reflected。
def orm_initialization(engine):
import cPickle
with open('/tmp/metadata') as meta_file:
meta = cPickle.load(meta_file)
meta.bind = engine
Reflected.metadata = meta
Reflected.prepare(engine) # reflect DB tables metadata
S = sessionmaker()
s = S(bind=engine)
....
但后来我收到错误
ArgumentError:无法确定关系上父/子表之间的连接条件...指定'primaryjoin'表达式。如果存在'secondary',则还需要'secondaryjoin'。
我做错了什么?如何正确加载pickled元数据?