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 [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.