Is it possible to unload declarative classes in SQLAlchemy?

Im working on a library where the user can simply declare several classes that are automatically supported by the database. In short, somewhere hidden in the code, there is

from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class LibraryBase(Base): # important library stuff 

and the user must execute

 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 

In a static environment, for example. the user created a single file with all personal classes and imports this file, this works very well. All class names are fixed, and SQLAlchemy knows how to map each class.

In an interactive environment, everything is different: now there is a chance that the class will be defined twice. Both classes can have different modules; but still SQLAlchemy will complain:

SAWarning: The class name MyStuff is already in the registry of this declarative database, displayed in <class 'OtherModule.MyStuff'>

Is there any way to handle this? Is there any way to unload a class from declarative_base so that I can exchange its definition with a new one?

+8
python class mapping declarative sqlalchemy
source share
3 answers

It looks like I'm not sure if this even works, but I think you want

sqlalchemy.orm.instrumentation.unregister_class()

http://hg.sqlalchemy.org/sqlalchemy/file/762548ff8eef/lib/sqlalchemy/orm/instrumentation.py#l466

+2
source share

You can use:

 sqlalchemy.orm.instrumentation.unregister_class(cl) del cl._decl_class_registry[cl.__name__] 

The first line is to prevent the accidental use of your unregistered class. The second will unlock and prevent the warning.

+2
source share

In my project, I use this solution. If the library contains columns defined as mixin from declared_attr and target mapper created using type , calling with the bases, as a result I have a full functional mapper.

 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() 
0
source share

All Articles