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. 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. 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)
models.session.add(foo_obj)
models.session.flush()
class Bar(BaseBar):
pass
class FooBar(BaseFooBar):
pass
The original error I was getting was something like this:
"InvalidRequestError: One or more mappers failed to initialize - can't
proceed with initialization of other mappers. Original exception was:
Multiple classes found for path "Foo" in the registry of this declarative
base. Please use a fully module-qualified path."
So I tried putting the full path in the relationships. Then it started
giving me an error like this:
"FlushError: Attempting to flush an item of type <class
'main_module.models.Foo'> as a member of collection "FooBar.foos". Expected
an object of type <class 'separate_library.models.Foo'> or a polymorphic
subclass of this type. If <class 'main_module.models.Foo'> is a subclass of
<class 'separate_library.models.Foo'>, configure mapper "Mapper|Foo|foos"
to load this subtype polymorphically, or set enable_typechecks=False to
allow any subtype to be accepted for flush.
Essentially, the main problem is getting the classes in the main module to
point to and act like the model classes. For example, when I try to create
relationships, it says it expected an object of type
'separate_library.models.Foo' instead of 'main_module.models.Foo'.
Additionally, in the polymorphic relationships, I can't get the
polymorphic_identity to populate for the polymorphic_on column. For
example, Bar in the main repository will have the 'type' column empty when
the object is initially created.
One idea I tried was to add a metaclass to the declarative base in the
models library and modify the mappers in the __init__ method during their
initialization. I made progress this way, but haven't gotten it to work
completely.
Sorry for the complex explanation, but this is a complex problem. I am not
able to change anything about the models or the use case, unfortunately. I
have to work within these constraints. If anyone can offer ideas on how to
configure the mappers for the classes in the main repository to act like
the models in the model library, I would be very grateful.
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.