association proxy documents the "proxy_factory" attribute for this purpose. see below.
from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.associationproxy import association_proxy, _AssociationSet import operator Base = declarative_base() class AppenderAssociationSet(_AssociationSet): """subclass _AssociationSet to adapt some set methods to that of AppenderQuery. """ def add(self, object_): self.col.append(self._create(object_)) def extend(self, objects): for obj in objects: self.col.append(self._create(obj)) def clear(self): """"the set assignment needs 'clear' but we dont really have a consistent way to do that with AppenderQuery. """ def set_factory(lazy_collection, creator, value_attr, assoc_prox): """Factory for associationproxy collections.""" # does "return MyObject.<value_attr>" getter = operator.attrgetter(value_attr) # does "MyObject.<value_attr> = <v>" setter = lambda o, v: setattr(o, value_attr, v) return AppenderAssociationSet(lazy_collection, creator, getter, setter, assoc_prox) class A(Base): __tablename__ = "a" id = Column(Integer, primary_key=True) bs = relationship("B", lazy="dynamic") cs = association_proxy("bs", "c", proxy_factory=set_factory) class B(Base): __tablename__ = "b" id = Column(Integer, primary_key=True) def __init__(self, c): self.c = c a_id = Column(Integer, ForeignKey('a.id')) c_id = Column(Integer, ForeignKey('c.id')) c = relationship("C") class C(Base): __tablename__ = "c" id = Column(Integer, primary_key=True) e = create_engine("sqlite://", echo=True) Base.metadata.create_all(e) c1, c2, c3 = C(), C(), C() s = Session(e) s.add_all([ A(cs=set([c1, c2])) ]) s.commit() a1 = s.query(A).first() print a1.cs a1.cs.add(c3) s.commit() print a1.cs.difference([c1]) On Jul 17, 2012, at 6:26 PM, Jon Parise wrote: > I have a similar use case, and aside from introducing a duplicate "non-lazy" > relationship to back the association_proxy, I haven't found a solution. > > Does anyone have a more elegant approach? > > On Saturday, February 11, 2012 12:15:38 PM UTC-8, Mark Friedenbach wrote: > Hi, > > Is it possible to have an association_proxy (in the association object > pattern) that emulates a set-based collection if it goes through a > lazy='dynamic' relationship? I can't for the life of me find a way to > make this work (setting collection_class on the dynamic relationship > doesn't seem to do anything). > > Here's some example code of what I'm trying to do, extracted from the > actual project: > > class ProofOfWork(object): > blocks = association_proxy('Intermediatory_nodes', 'block') > proof_of_work = Table('proof_of_work', db.metadata) > mapper(ProofOfWork, proof_of_work, properties={ > 'Intermediatory_nodes': relationship(lambda: Intermediatory, > lazy = 'dynamic'), > }) > > class Block(object): > proof_of_works = association_proxy('Intermediatory_nodes', > 'proof_of_work') > block = Table('block', db.metadata) > mapper(Block, block, properties={ > 'Intermediatory_nodes': relationship(lambda: Intermediatory, > lazy = 'dynamic'), > }) > > class Intermediatory(object): > pass > intermediatory = Table('intermediatory', db.metadata, > Column('proof_of_work_id', Integer, > ForeignKey('proof_of_work.id'), > nullable = False), > Column('block_id', Integer, > ForeignKey('block.id')), > ) > mapper(Intermediatory, intermediatory, properties={ > 'proof_of_work': relationship(lambda: ProofOfWork, > back_populates = 'Intermediatory_nodes', > remote_side = lambda: proof_of_work.c.id), > 'block': relationship(lambda: Block, > back_populates = 'Intermediatory_nodes', > remote_side = lambda: block.c.id), > }) > > How can I make ProofOfWork.blocks and Block.proof_of_works return an > _AssociationSet instead of _AssociationList? > > Cheers, > Mark > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To view this discussion on the web visit > https://groups.google.com/d/msg/sqlalchemy/-/gs9rqWLKooQJ. > To post to this group, send email to sqlalchemy@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. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@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.