What I aiming for is to provide users a library of base class(es), which
are mapped using SQLAlchemy. The classes are then meant to be extended by
users with business logic. I am not hell bent on using inheritance for
this, but for now I went with your __abstract__ = True solution only in a
somewhat inverted way. I had to use @declared_attr decorators to wrap
around relationships in that class. I also had to move back-refed
relationship definitions from referencing classes to here because the name
of the concrete class is not known.
There are some problems with this approach. First, it implies that only
some of the classes can be abstract or we may not be able to construct all
relationships. Secondly, within the scope of one application there can be
only one derived class per each abstract class or we will face issues with
create_all wanting to create the users table again. Any ideas how to
overcome that? Below is the modified example.
Thank you very much for helping.
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import Session, relationship, backref
Base = declarative_base()
class User(Base):
__abstract__ = True
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
password = Column(String(12))
@declared_attr
def addresses(self):
return relationship('Address', backref=backref('user',
uselist=False))
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
class Thinker(User):
thought = 'Thoughts are not to be persited'
e = create_engine('sqlite:///', echo=True)
Base.metadata.bind = e
Base.metadata.create_all()
t = Thinker(name='Descartes')
s = Session(bind=e)
s.add(t)
s.commit() # no problem
a = Address(user=t, email_address='[email protected]')
s.commit() # No more FlushError
On Tuesday, June 24, 2014 6:39:03 PM UTC-4, Michael Bayer wrote:
>
>
> On 6/24/14, 5:44 PM, Victor Olex wrote:
>
> So, what is the right idiom for building SQLAlchemy persistence into
> classes that need to do more than just that i.e. have run-time state. I was
> hoping that deriving from SQLAlchemy model classes, but that does not seem
> to be it. Another option would be to encapsulate a model class within the
> "runtime" class, but that way we need to wrap SQLAlchemy session and
> queries functionality into some helper functions.
>
> Typically the class that has whatever methods and state that you want is
> also mapped directly. There's no need to have "User" and "Thinker" as
> separate classes.
>
> if you truly don't want anything to do with persistence visibly present on
> classes, that's what classical mapping using mapper() and Table was
> designed for, or alternatively you can make a business-level class as
> abstract, or as a mixin:
>
> class MyClass(Base):
> __abstract__ = True
>
> def my_business_method(self):
> #...
>
> class MyMappedClass(MyClass):
> # ...
>
> depends really on how you need the two roles of business logic and
> persistence to be separate. Putting them all together is obviously the
> most simplistic but that's what most people do, unless you're trying to do
> something more J2EE-ish.
>
>
>
>
>
> On Friday, May 30, 2014 2:11:53 PM UTC-4, Michael Bayer wrote:
>>
>> yep… here’s the error:
>>
>> sqlalchemy.orm.exc.FlushError: Attempting to flush an item of type
>> <class '__main__.Thinker'> as a member of collection "Address.user".
>> Expected an object of type <class '__main__.User'> or a polymorphic
>> subclass of this type. If <class '__main__.Thinker'> is a subclass of
>> <class '__main__.User'>, configure mapper "Mapper|User|users" to load this
>> subtype polymorphically, or set enable_typechecks=False to allow any
>> subtype to be accepted for flush.
>>
>>
>> enable_typechecks=False disables this check:
>>
>> user = relationship("User", enable_typechecks=False,
>> backref=backref('addresses', order_by=id))
>>
>> it just means that later on, when you hit some_address.user, you may
>> get a User back, not a Thinker (or you will, if it hasn’t been expired.
>> you can’t rely on it being consistent). If that’s OK, then set the flag -
>> it just wants to check that this is what you intend.
>>
>>
>>
>>
>> On May 30, 2014, at 1:51 PM, Victor Olex <[email protected]>
>> wrote:
>>
>> Hello all, long time no see...
>>
>> Is it OK to create classes, which inherit from mapped classes, but are
>> not meant to be persited and how to do it as to avoid FlushError on related
>> classes?
>>
>> from sqlalchemy import *
>> from sqlalchemy.ext.declarative import declarative_base
>> from sqlalchemy.orm import Session, relationship, backref
>>
>> Base = declarative_base()
>>
>> class User(Base):
>> __tablename__ = 'users'
>> id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
>> name = Column(String(50))
>> fullname = Column(String(50))
>> password = Column(String(12))
>>
>> class Address(Base):
>> __tablename__ = 'addresses'
>> id = Column(Integer, primary_key=True)
>> email_address = Column(String, nullable=False)
>> user_id = Column(Integer, ForeignKey('users.id'))
>> user = relationship("User", backref=backref('addresses', order_by=id))
>>
>> class Thinker(User):
>> thought = 'Thoughts are not to be persited'
>>
>> e = create_engine('sqlite:///', echo=True)
>> Base.metadata.bind = e
>> Base.metadata.create_all()
>>
>> t = Thinker(name='Descartes')
>> s = Session(bind=e)
>> s.add(t)
>> s.commit() # no problem
>> a = Address(user=t, email='[email protected]')
>> a = Address(user=t, [email protected]')
>> s.commit() # FlushError
>>
>> Thanks,
>>
>> V.
>>
>>
>> --
>> 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 http://groups.google.com/group/sqlalchemy.
>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>> --
> 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] <javascript:>.
> To post to this group, send email to [email protected]
> <javascript:>.
> Visit this group at http://groups.google.com/group/sqlalchemy.
> For more options, visit https://groups.google.com/d/optout.
>
>
>
--
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 http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.