Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-07-22 Thread Mike Bayer
the first error is because declarative isn't smart enough to figure out 
this many __abstract__ flags, and I'd support efforts to improve this. 
But if you pass __abstract__ = False in a few places that gives it the 
clues it needs to get to the second case (as well as removing the 
__abstract__ = True where not needed).


The second error is more simple, you need to define what table Coupe is 
mapped towards; if you want it to be single inheritance off of "cars" 
then you need to give it None for __tablename__:


class Vehicle(AbstractVehicle, Base):
pass


class Car(AbstractCar, Vehicle):
__abstract__ = False


class Coupe(AbstractCoupe, Car):
__abstract__ = False
__tablename__ = None






BEGIN (implicit)
2016-07-22 09:35:58,641 INFO sqlalchemy.engine.base.Engine INSERT INTO 
vehicles (id, name, type) VALUES (?, ?, ?)
2016-07-22 09:35:58,641 INFO sqlalchemy.engine.base.Engine (10, 'test', 
'coupe')
2016-07-22 09:35:58,642 INFO sqlalchemy.engine.base.Engine INSERT INTO 
cars (id) VALUES (?)

2016-07-22 09:35:58,642 INFO sqlalchemy.engine.base.Engine (10,)
2016-07-22 09:35:58,642 INFO sqlalchemy.engine.base.Engine COMMIT
2016-07-22 09:35:58,643 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2016-07-22 09:35:58,644 INFO sqlalchemy.engine.base.Engine SELECT 
cars.id AS cars_id, vehicles.id AS vehicles_id, vehicles.name AS 
vehicles_name, vehicles.type AS vehicles_type

FROM vehicles JOIN cars ON vehicles.id = cars.id
WHERE vehicles.type IN (?)
 LIMIT ? OFFSET ?
2016-07-22 09:35:58,644 INFO sqlalchemy.engine.base.Engine ('coupe', 1, 0)
<__main__.Coupe object at 0x7f4a81e5afd0>





On 07/21/2016 07:22 PM, Angie Ellis wrote:

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

Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-07-21 Thread Angie Ellis
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 
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)
>> 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 > >"]),
>>
>> )

Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-06-27 Thread Mike Bayer
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)
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 > 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
  

Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-06-27 Thread Angie Ellis
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 
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 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", 

Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-06-22 Thread Mike Bayer



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 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.


So the way you have it is that those are mixins, which is fine, and I 
guess that's how we need it because you want to keep multiple Base's in 
play at the same time.   You don't need the __abstract__ keyword in that 
case.  So to map that looks like the following POC:


from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.declarative import declared_attr


class AbstractFoo(object):
__tablename__ = "foo"

id = Column(Integer, primary_key=True)
type = Column(String)

@declared_attr
def foo_bar_id(cls):
return Column(Integer, ForeignKey("foo_bar.id"))

@declared_attr
def foo_bar(cls):
return relationship("FooBar", backref=backref("foo"))

__mapper_args__ = {"polymorphic_on": type}


class AbstractBar(AbstractFoo):
__mapper_args__ = {"polymorphic_identity": "bar"}


class AbstractFooBar(object):
__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

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)

s.add(Bar(foo_bar=FooBar()))

s.commit()
s.close()

b1 = s.query(Foo).first()
print b1
print b1.foo_bar







Thanks,
Angie

On Fri, Jun 3, 2016 at 12:38 PM, Mike Bayer > wrote:



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 

Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-06-22 Thread Angie Ellis
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 Bayer 
wrote:

>
>
> 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)
>> 

Re: [sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-06-03 Thread Mike Bayer



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)
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."


that only happens if someone is using a string name inside of 
relationship(), like this:


foobars = relationship("Foo")

If the "library" is doing that, and you can't change it, easy solution, 
use a different name for your "Foo" that's also in the 3rd party 
library.   Or declare your classes against a different base:


Base = declarative_base()

class Foo(other_package.Foo, Base):
# ...


class Bar(other_package.Bar, Base):
# ...

I'm not 100% sure that will work but there's probably a way to make that 
work.






So I tried putting the full path in the relationships. Then it started
giving me an error like this:


oh, OK, then you're fine there.




 "FlushError: Attempting to flush an item of type  as a member of collection "FooBar.foos".
Expected an object of type  or a
polymorphic subclass of this type. If 
is a subclass of , configure mapper
"Mapper|Foo|foos" to load this subtype polymorphically, or set
enable_typechecks=False to allow any subtype to be accepted for flush.


Well, when this relationship loads, you'd like it to return a list of 
main_module.models.Foo objects and not separate_library.models.Foo. 
Your model here needs to have a 

[sqlalchemy] Is there a way to create custom classes that inherit from sqlalchemy models in external library?

2016-06-03 Thread Angie E
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  as a member of collection "FooBar.foos". Expected 
an object of type  or a polymorphic 
subclass of this type. If  is a subclass of 
, 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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to