我正在开发一个库,用户可以简单地声明一些由数据库自动支持的类。简而言之,隐藏在代码中的地方有
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class LibraryBase(Base):
# important library stuff
然后用户应该
class MyStuff(LibraryBase):
# important personal stuff
class MyStuff_2(LibraryBase):
# important personal stuff
mystuff = MyStuff()
Library.register(mystuff)
mystuff.changeIt() # apply some changes to the instance
Library.save(mystuff) # and save it
# same for all other classes
在静态环境中,例如用户创建了一个包含所有个人类的文件并导入了该文件,这非常有效。所有类名都是固定的,SQLAlchemy知道如何映射每个类。
在交互式环境中,情况有所不同:现在,有可能两次定义一个类。这两个类可能有不同的模块;但SQLAlchemy仍会抱怨:
SAWarning:类名'MyStuff'已经在此声明基础的注册表中,映射到< class'OtherModule.MyStuff'>
有没有办法解决这个问题?我可以以某种方式从其declarative_base
中卸载一个类,以便我可以用一个新的交换它的定义吗?
答案 0 :(得分:2)
看起来,我并不确定这是否有效,但我认为你想要的是
sqlalchemy.orm.instrumentation.unregister_class()
http://hg.sqlalchemy.org/sqlalchemy/file/762548ff8eef/lib/sqlalchemy/orm/instrumentation.py#l466
答案 1 :(得分:2)
您可以使用:
sqlalchemy.orm.instrumentation.unregister_class(cl)
del cl._decl_class_registry[cl.__name__]
第一行是防止意外使用您的未注册课程。第二次注销并将阻止警告。
答案 2 :(得分:0)
在我的项目中,我使用此解决方案。
库指定的列由declared_attr
定义为mixin,type
创建的目标映射器使用base调用,结果我有完整的功能映射器。
from sqlalchemy import create_engine, BigInteger, Column
from sqlalchemy.orm import sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.declarative import declared_attr
Base = declarative_base()
class LibraryBase(object):
__tablename__ = 'model'
@declared_attr
def library_field(self):
return Column(BigInteger)
class MyLibrary(object):
@classmethod
def register(cls, entity):
tablename = entity.__tablename__
Mapper = type('Entity_%s' % tablename, (Base, LibraryBase, entity), {
'__tablename__': tablename,
'id': Column(BigInteger, primary_key=True),
})
return Mapper
@classmethod
def setup(cls):
Base.metadata.create_all()
class MyStaff(object):
__tablename__ = 'sometable1'
@declared_attr
def staff_field(self):
return Column(BigInteger)
def mymethod(self):
print('My method:', self)
class MyStaff2(MyStaff):
__tablename__ = 'sometable2'
if __name__ == '__main__':
engine = create_engine('sqlite://', echo=True)
Base.metadata.bind = engine
Session = scoped_session(sessionmaker(bind=engine))
session = Session()
# register and install
MyStaffMapper = MyLibrary.register(MyStaff)
MyStaffMapper2 = MyLibrary.register(MyStaff2)
MyLibrary.setup()
MyStaffMapper().mymethod()
MyStaffMapper2().mymethod()
session.query(MyStaffMapper.library_field) \
.filter(MyStaffMapper.staff_field != None) \
.all()