On 11/03/2015 07:32 AM, Mattias Lagergren wrote:
> Hi Michael,
>
> I've been putting together a self-contained example. If you save it to a
> file test_model you should be able to run it:
what's the SQL output with echo=True on the engine? is the subquery for
context rendered in the SQL and is it correct?
What happens if you load just a Context object by itself?
the example here isn't exactly "self contained" because it loads data
that's not there. Also there's no need to "import test_model", "cls",
right there is the Context object.
What happens if you run the example using no inheritance at all?
It might be possible that __declare_last__() isn't appropriate here, can
you try just saying "Context.link = column_property()"... right after
you declare Context?
>
> |
>
> importsqlalchemy
> importsqlalchemy.orm
> importsqlalchemy.inspection
> importsqlalchemy.ext.declarative
>
> DATABASE_URL =<database-url>
>
> Base=sqlalchemy.ext.declarative.declarative_base()
>
>
> classContext(Base):
> '''Represent a context.'''
>
> context_type =sqlalchemy.Column(
> sqlalchemy.types.Unicode(32),nullable=False
> )
>
> __mapper_args__ ={
> 'polymorphic_on':context_type,
> 'polymorphic_identity':'context'
> }
>
> __tablename__ ='context'
>
> name =sqlalchemy.Column(
> sqlalchemy.types.Unicode(255),default=u'',nullable=False
> )
>
> id =sqlalchemy.Column(
> sqlalchemy.types.CHAR(36),primary_key=True
> )
>
> @classmethod
> def__declare_last__(cls):
> '''Return link expression query.'''
>
> # Import this module.
> importtest_model ascontext
> context =sqlalchemy.orm.aliased(context.Context.__table__)
>
> # My real use-case is more complicated and involves a lot of joinst to
> # other tables, but this example reproduces the issue.
> cls.link =sqlalchemy.orm.column_property(
> sqlalchemy.select(
> [
context.c.name +' '+context.c.context_type],
> ).label('link')
> )
>
>
> classTask(Context):
> '''Represent a task.'''
>
> __tablename__ ='task'
>
> __mapper_args__ ={
> 'polymorphic_identity':'task'
> }
>
> taskid =sqlalchemy.Column(
> sqlalchemy.types.CHAR(36),
> sqlalchemy.ForeignKey('
context.id'),
> primary_key=True
> )
>
>
> classAsset(Base):
> '''Represent an Asset.'''
>
> __tablename__ ='asset'
>
> assetid =sqlalchemy.Column(
> sqlalchemy.types.CHAR(36),primary_key=True
> )
>
> context_id =sqlalchemy.Column(
> sqlalchemy.CHAR(36),sqlalchemy.ForeignKey('
context.id')
> )
>
> parent =sqlalchemy.orm.relationship(
> 'Context'
> )
>
>
> if__name__ =='__main__':
> print'Loaded attributes: '
>
> # Create engine.
> engine =sqlalchemy.create_engine(
> DATABASE_URL
> )
> Session=sqlalchemy.orm.sessionmaker(bind=engine)
> session =Session()
>
> entity =session.query(
> Asset
> ).options(
> sqlalchemy.orm.joinedload('parent')
> ).first()
>
> state =sqlalchemy.inspection.inspect(entity.parent)
> forattribute instate.attrs:
> is_loaded =(
> attribute.loaded_value isnot
> sqlalchemy.orm.base.NO_VALUE
> )
> ifis_loaded:
> printattribute.key
>
> |
>
>
>
>
> On Monday, November 2, 2015 at 3:16:07 PM UTC+1, Mattias Lagergren wrote:
>
> Hi,
>
> I'm trying to use load_only and joinedload on a relationship
> model.Asset.parent. The parent relation is polymorphic and can be
> either Task or Project with the common Base class called Context.
>
> |
> importsqlalchemy.orm
> importsqlalchemy.inspection
>
> entity =model.session.query(
> model.Asset
> ).options(
> sqlalchemy.orm.joinedload('parent').load_only(
> 'context_type','name','link'
> )
> ).first()
>
> state =sqlalchemy.inspection.inspect(entity.parent)
> forattribute instate.attrs:
> is_loaded =(
> attribute.loaded_value isnot
> sqlalchemy.orm.base.NO_VALUE
> )
> ifis_loaded:
> printattribute.key
>
> # Output:
> id
> taskid
> name
> context_type
>
> |
>
> The id, name and context_type is from Context. And taskid is primary
> key on the taskid and is a foreignkey to the
context.id
> <
http://context.id>. As you can see "name" loads fine but "link"
> attribute is not loaded. The "link" column is added as a
> column_property to Context using a __declare_last__.
>
> These are simplified versions of the classes:
>
> |
>
> classContext(Base):
> '''Represent a context.'''
> context_type =Column(Unicode(32),nullable=False)
>
> __mapper_args__ ={
> 'polymorphic_on':context_type,
> 'polymorphic_identity':'context'
> }
>
> name =Column(Unicode(255),default=u'',nullable=False)
>
> @declared_attr
> defid(cls):
> returnColumn(CHAR(36),primary_key=True,default=lambda:str(uuid()))
>
> @classmethod
> def__declare_last__(cls):
> '''Return link expression query.'''
>
> ...
>
> cls.link =column_property(
> sqlalchemy.type_coerce(
> query,LinkTypeDecorator
> ).label('link')
> )
>
> classTask(Context):
> '''Represent a task.'''
>
> taskid =Column(
> types.CHAR(36),
> ForeignKey('
context.id <
http://context.id>'),
> primary_key=True
> )
>
> __mapper_args__ ={
> 'polymorphic_identity':'task'
> }
>
>
> classAsset(Base):
> '''Represent an Asset.'''
>
> context_id =sqlalchemy.Column(
> sqlalchemy.CHAR(36),sqlalchemy.ForeignKey('
context.id
> <
http://context.id>')
> )
>
> parent =relationship('Context',backref=backref('assets'))
>
> |
>
> Can you see if I'm doing something wrong?
>