Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?
Adding __abstract__ = True to the AbstractCoupe did seem to resolve those errors, but it gave me a new one: from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declared_attr class AbstractVehicle(object): __tablename__ = "vehicles" id = Column(Integer, primary_key=True) name = Column(String, nullable=False) type = Column(String) __mapper_args__ = {"polymorphic_on": type} class AbstractCar(AbstractVehicle): __tablename__ = "cars" id = Column("id", Integer, primary_key=True) __mapper_args__ = {"polymorphic_identity": "car"} __table_args__ = ( ForeignKeyConstraint(["id"], ["vehicles.id"]), ) class AbstractCoupe(AbstractCar): __abstract__ = True __mapper_args__ = {"polymorphic_identity": "coupe"} Base = declarative_base() class Vehicle(AbstractVehicle, Base): pass class Car(AbstractCar, Vehicle): pass class Coupe(AbstractCoupe, Car): pass if __name__ == "__main__": e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) s = Session(e) s.add(Coupe(id=10, name="test")) s.commit() s.close() b1 = s.query(Coupe).first() print(b1) Traceback (most recent call last): File "test.py", line 53, in s.add(Coupe(id=10, name="test")) File "", line 4, in __init__ File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/orm/state.py", line 306, in _initialize_instance manager.dispatch.init_failure(self, args, kwargs) File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__ compat.reraise(exc_type, exc_value, exc_tb) File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/util/compat.py", line 184, in reraise raise value File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/orm/state.py", line 303, in _initialize_instance return manager.original_init(*mixed[1:], **kwargs) File "", line 6, in __init__ File "", line 6, in __init__ File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/ext/declarative/base.py", line 649, in _declarative_constructor setattr(self, k, kwargs[k]) File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/orm/attributes.py", line 223, in __set__ self.impl.set(instance_state(instance), AttributeError: 'NoneType' object has no attribute 'set' When I take out the arguments and just run: s.add(Coupe()) It gives me this: Traceback (most recent call last): File "test.py", line 53, in s.add(Coupe()) File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 1588, in add self._save_or_update_state(state) File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 1602, in _save_or_update_state mapper = _state_mapper(state) File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/util/langhelpers.py", line 754, in __get__ obj.__dict__[self.__name__] = result = self.fget(obj) File "/mnt/hgfs/Documents/git/cc-mysql/env/lib/python3.5/site-packages/sqlalchemy/orm/instrumentation.py", line 116, in mapper raise exc.UnmappedClassError(self.class_) sqlalchemy.orm.exc.UnmappedClassError: Class '__main__.Coupe' is not mapped Sorry for the intermittent responses. Thanks so much for your help! On Mon, Jun 27, 2016 at 2:21 PM, Mike Bayer <mike...@zzzcomputing.com> wrote: > I think it's OK to add __abstract__ to those mixins, in this case it seems > like the (pretty complicated) class graph is adding up to something that > causes declarative to see AbstractCar as mapped class thus a "car" table is > added. Adding __abstract__ to AbstractCoupe seems to resolve. > > > > > On 06/27/2016 05:10 PM, Angie Ellis wrote: > >> I implemented the changes you suggested, but I am running into errors >> with some polymorphic relations. Using a different theme, here is an >> example: >> >> >> class AbstractVehicle(object): >> __tablename__ = "vehicles" >> >> id = Column(Integer, primary_key=True) >> nam
Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?
I implemented the changes you suggested, but I am running into errors with some polymorphic relations. Using a different theme, here is an example: class AbstractVehicle(object): __tablename__ = "vehicles" id = Column(Integer, primary_key=True) name = Column(String, nullable=False) type = Column(String) __mapper_args__ = {"polymorphic_on": type} class AbstractCar(AbstractVehicle): __tablename__ = "cars" id = Column("id", Integer, primary_key=True) __mapper_args__ = {"polymorphic_identity": "car"} __table_args__ = ( ForeignKeyConstraint(["id"], ["vehicles.id"]), ) class AbstractCoupe(AbstractCar): __mapper_args__ = {"polymorphic_identity": "coupe"} Base = declarative_base() class Vehicle(AbstractVehicle, Base): pass class Car(AbstractCar, Vehicle): pass class Coupe(AbstractCoupe, Car): pass This resulted in the following error: File ".../model/vehicle.py", line 255, in class Coupe(AbstractCoupe, Car): File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 55, in __init__ _as_declarative(cls, classname, cls.__dict__) File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 88, in _as_declarative _MapperConfig.setup_mapping(cls, classname, dict_) File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 103, in setup_mapping cfg_cls(cls_, classname, dict_) File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 131, in __init__ self._setup_table() File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 395, in _setup_table **table_kw) File ".../env/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 398, in __new__ "existing Table object." % key) InvalidRequestError: Table 'cars' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object. After adding "extend_existing=True" to the AbstractCoupe model, I received this error: File ".../model/vehicle.py", line 255, in class Coupe(AbstractCoupe, Car): File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 55, in __init__ _as_declarative(cls, classname, cls.__dict__) File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 88, in _as_declarative _MapperConfig.setup_mapping(cls, classname, dict_) File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 103, in setup_mapping cfg_cls(cls_, classname, dict_) File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 135, in __init__ self._early_mapping() File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 138, in _early_mapping self.map() File ".../env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 530, in map **self.mapper_args File "", line 2, in mapper File ".../env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 627, in __init__ self._configure_properties() File ".../env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1292, in _configure_properties self._adapt_inherited_property(key, prop, False) File ".../env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1514, in _adapt_inherited_property self._configure_property(key, prop, init=False, setparent=False) File ".../env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1541, in _configure_property prop.columns[0]) File ".../env/lib/python2.7/site-packages/sqlalchemy/sql/selectable.py", line 476, in corresponding_column if self.c.contains_column(column): File ".../env/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 754, in __get__ obj.__dict__[self.__name__] = result = self.fget(obj) File ".../env/lib/python2.7/site-packages/sqlalchemy/sql/selectable.py", line 553, in columns return self._columns.as_immutable() AttributeError: 'Table' object has no attribute '_columns' Is there a way to fix or work around this? Thanks, Angie On Wed, Jun 22, 2016 at 7:27 PM, Mike Bayer <mike...@zzzcomputing.com> wrote: > > > On 06/22/2016 04:53 PM, Angie Ellis wrote: > >> Mike, >> >> Thank you for the response! I do have control over the external library. >> I like your idea having both the abstract classes and concrete classes >> available in the library because I have use cases for both in my >> applications. However, I'm not qu
Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?
Mike, Thank you for the response! I do have control over the external library. I like your idea having both the abstract classes and concrete classes available in the library because I have use cases for both in my applications. However, I'm not quite sure how to configure the inheritance and declarative base. What am I doing wrong here? class AbstractFoo(object): __abstract__ = True __tablename__ = "foo" id = Column(Integer, primary_key=True) type = Column(String) foo_bar_id = Column(Integer, ForeignKey("foo_bar.id")) foo_bar = relationship("FooBar", backref=backref("foo")) __mapper_args__ = {"polymorphic_on": type} class AbstractBar(object): __abstract__ = True __mapper_args__ = {"polymorphic_identity": "bar"} class AbstractFooBar(object): __abstract__ = True __tablename__ = "foo_bar" id = Column(Integer, primary_key=True) Base = declarative_base() class Foo(AbstractFoo, Base): pass class Bar(AbstractBar, Foo): pass class FooBar(AbstractFooBar, Base): pass Does AbstractBar need to inherit from AbstractFoo? Do the abstract classes need to inherit their own declarative base? Do I need to change the inheritance order? The classes Foo, Bar, and FooBar are not getting mapped. Thanks, Angie On Fri, Jun 3, 2016 at 12:38 PM, Mike Bayerwrote: > > > On 06/03/2016 02:44 PM, Angie E wrote: > >> Rather than creating mixin classes that models inherit from, I have a >> use case that requires me to configure classes the other way around. The >> classes that would normally be mixin classes need to be the classes that >> inherit from the models as well as the class that model objects are >> created from. This is because the models and the mapper configurations >> are in an external library from the main repository. I need to pass in >> the host for the engine from the main repository to the models library >> before any of the models are loaded so they can load with the >> declarative base already configured. >> > > I hope you are using reflection for these models, otherwise there's no > reason to have a depedency on the Engine for the model declaration. > > > After the engine information is > >> passed in, the session, Base class, and everything is created within a >> sort of base class that the models inherit from. Here is a simplified >> example: >> >> >> class SQLAlchemyBase(object): >> metadata = None >> Session = None >> Base = object >> sessionfactory = sessionmaker() >> >> def initialize(self, host): >> engine = create_engine(host) >> self.metadata = MetaData(bind=engine) >> self.Session = scoped_session(self.sessionfactory) >> self.Base = declarative_base(metadata=self.metadata) >> >> models = SQLAlchemyBase() >> >> (The models inherit from models.Base) >> >> >> So the SQLAlchemyBase will be imported into the main repository, the >> initialize method will be called, passing in the host for the engine, >> and the models can then be imported. >> > > Looks like no reflection taking place. I'd do away with the > MetaData(bind=engine), and just have the engine as part of the > sessionmaker(), and the sessionmaker() here also doesn't need to have > anything to do with the "library", if the "library" is just defining model > classes. > > The "bound metadata" pattern is highly discouraged in modern SQLAlchemy > because it leads to this kind of confusion, e.g. that one needs an Engine > in order to declare models. You don't. > > > > > > > The main repository has its own > >> classes with the same names as the models and have additional methods >> that a normal mixin class would have to extend functionality. However, I >> am unable to create model objects using the classes in the main >> repository because I can't get the mappers to play nice with this >> unusual inheritance that extends from the external models library. >> Additionally, in the models library, there are models that have multiple >> levels of inherited polymorphic relationships. Here is an example that >> is similar one of the more basic inherited polymorphic relationships: >> >> >> **Models Library** >> >> class Foo(models.Base): >> >> __tablename__ = "foo" >> id = Column(Integer, primary_key=True) >> type = Column(String) >> foo_bar_id = Column(Integer, ForeignKey("foo_bar.id")) >> foo_bar = relationship(Foo, backref=backref("foos")) >> >> __mapper_args__ = {"polymorphic_on": type} >> >> >> class Bar(Foo): >> >> __mapper_args__ = {"polymorphic_identity": "bar"} >> >> >> class FooBar(models.Base): >> >> __tablename__ = "foo_bar" >> id = Column(Integer, primary_key=True) >> >> >> **Main Repository** >> >> from separate_library.models import models, Foo as BaseFoo, Bar as >> BaseBar, FooBar as BaseFooBar >> >> >> class Foo(BaseFoo): >> >> @classmethod >> def custom_create_method(cls, **kw): >> foo_obj = cls(**kw) >>