On Oct 18, 4:06 pm, Michael Bayer <mike...@zzzcomputing.com> wrote: > 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) > }) >
Yes, I would like to maintain the Association Object pattern since there is other data that is stored in the association table. This second approach works well, thanks for your help. > > > > 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 sqlalch...@googlegroups.com. > > To unsubscribe from this group, send email to > > sqlalchemy+unsubscr...@googlegroups.com. > > For more options, visit this group > > athttp://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 sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.