On Oct 18, 2010, at 2:46 PM, Jasper K wrote:
> Hi Group,
>
> I am using SqlAlchemy 0.5.8
>
> I get an "(OperationalError) no such column: child.child_id" error
> when trying to eagerload a viewonly many-to-many relationship that
> uses the Association Object pattern with a custom secondaryjoin
> condition (http://www.sqlalchemy.org/docs/05/mappers.html#association-
> object).
>
> The following example demonstrates the issue. It consists of three
> tables: Parent, Child, Association. The goal is to have a mapped
> property on the Parent table that filters out certain associations
> based on properties stored in the Child table (the Parent is trying to
> eagerload all it's "nice children"). It seems the SQL that gets
> generated during the eagerload fails to include the Child table.
> However when used without the eagerload everything works as expected.
> I have not tried this with the newer SqlAlchemy but I would like to
> get it working on 0.5.8 if possible.
So "secondary" and "secondaryjoin" only apply to this exact pattern:
Parent -> association table -> Child
your example is doing this:
Parent -> association table -> Association Object
The correct mapping, using "secondary", would be:
mapper(Parent, parent_table, properties={
'nice_children': relation(Child, lazy=True,
secondary=association_table,
primaryjoin=parent_table.c.parent_id==association_table.c.parent_id,
secondaryjoin=and_(association_table.c.child_id==child_table.c.child_id,
child_table.c.status==NICE),
viewonly=True)
})
If you'd like to maintain that "nice_children" returns "Association" objects,
you'd have to get the link to "child" to be referenced inside the primaryjoin,
as the endpoint of the JOIN must be the target of the relation():
mapper(Parent, parent_table, properties={
'nice_children': relation(Association, lazy=True,
primaryjoin=and_(
parent_table.c.parent_id==association_table.c.parent_id,
association_table.c.child_id.in_(select([child_table.c.child_id]).where(child_table.c.status==NICE))
),
viewonly=True)
})
>
> Any help is much appreciated,
>
> Thanks
>
>
> from sqlalchemy import Table, Column, String, Integer, MetaData,
> ForeignKey, create_engine, and_
> from sqlalchemy.orm import mapper, relation, sessionmaker, eagerload
>
> engine = create_engine('sqlite:///:memory:', echo=True)
> metadata = MetaData()
> Session = sessionmaker(bind=engine)
> session = Session()
>
> NICE = 'NICE'
> NAUGHTY = 'NAUGHTY'
>
> parent_table = Table('parent', metadata,
> Column('parent_id', Integer, primary_key=True),
> Column('name', String(32)))
>
> child_table = Table('child', metadata,
> Column('child_id', Integer, primary_key=True),
> Column('name', String(32)),
> Column('status', String(32)))
>
> association_table = Table('association', metadata,
> Column('id', Integer, primary_key=True),
> Column('parent_id', ForeignKey('parent.parent_id')),
> Column('child_id', ForeignKey('child.child_id')))
>
> class Parent(object):
> def __init__(self, name):
> self.name = name
>
> class Child(object):
> def __init__(self, name, status):
> self.name = name
> self.status = status
>
> class Association(object):
> def __init__(self, parent, child):
> self.parent = parent
> self.child = child
>
> mapper(Parent, parent_table, properties={
> 'nice_children': relation(Association, lazy=True,
> secondary=association_table,
>
> primaryjoin=parent_table.c.parent_id==association_table.c.parent_id,
>
> secondaryjoin=and_(association_table.c.child_id==child_table.c.child_id,
> child_table.c.status==NICE),
> viewonly=True)
> })
>
> mapper(Association, association_table, properties={
> 'child': relation(Child),
> 'parent': relation(Parent)
> })
>
> mapper(Child, child_table)
>
> metadata.create_all(engine)
>
>
> # CREATE ALL THE OBJECTS
>
> jack = Parent('Jack')
> kid1 = Child('Kid1', NICE)
> kid2 = Child('Kid2', NAUGHTY)
>
> session.add_all([jack, kid1, kid2])
> session.flush()
>
> assoc1 = Association(jack, kid1)
> assoc2 = Association(jack, kid2)
>
> session.add_all([assoc1, assoc2])
> session.flush()
>
> assert jack.nice_children
>
> session.expunge_all()
>
> # TEST THE EAGERLOADING
>
> parents = session.query(Parent).all()
> assert parents
> assert parents[0].nice_children[0].child.name == 'Kid1'
>
> # fails
> parents =
> session.query(Parent).options(eagerload('nice_children')).all()
> assert parents
> assert parents[0].nice_children[0].child.name == 'Kid1'
>
>
>
>
>
> --
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/sqlalchemy?hl=en.
>
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en.