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

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

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