I created a class CorrelatedProxy inheriting from AssociationProxy that 
allows the creator function to depend on the owner instance of the 
association proxy. Essentially it gets a attribute 'correlator' of the 
something like lambda x: lambda y, z: Constructor(x, y, z), and then 
intercepts the __get__ of AssociationProxy to create self.creator on the 
fly by applying the owner instance to the correlator. Now consider the code 
below.

from sqlalchemy.engine import create_engine
from sqlalchemy.ext.declarative.api import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.schema import Column, ForeignKey
from sqlalchemy.types import Integer
from sqlalchemy.ext.associationproxy import AssociationProxy

class CorrelatedProxy(AssociationProxy):
    def __init__(self, *args, **kw):
        self.correlator = kw.pop('correlator', None)
        AssociationProxy.__init__(self, *args, **kw)
    def __get__(self, obj, class_):
        if obj:
            self.creator = self.correlator(obj)
        return AssociationProxy.__get__(self, obj, class_)
        
def correlated_proxy(*args, **kw):
    return CorrelatedProxy(*args, **kw)


Base = declarative_base()

class A(Base):
    __tablename__ = 'table_a'
    id = Column(Integer, primary_key=True)
    ab = relationship('AB', backref = 'a', 
                      collection_class=attribute_mapped_collection('b'))
    abnum = correlated_proxy('ab', 'num', correlator=\
                             lambda a: lambda b, n: AB(a=a, b=b, num=n))
class AB(Base):
    __tablename__ = 'table_ab'
    num = Column(Integer)
    a_id = Column(Integer, ForeignKey('table_a.id'), primary_key=True)
    b_id = Column(Integer, ForeignKey('table_b.id'), primary_key=True)
    
class B(Base):
    __tablename__ = 'table_b'
    id = Column(Integer, primary_key=True)
    ab = relationship('AB', backref = 'b', 
                      collection_class=attribute_mapped_collection('a'))
    
    
if __name__ == '__main__':
    engine = create_engine('sqlite:///:memory:')
    Session = sessionmaker(engine)
    session = Session()
    Base.metadata.create_all(engine)
    
    aa = A()
    bb = B()
    aa.abnum[bb] = 1
    assert aa.abnum[bb] == aa.abnum[None] == 1

Basically, no matter, what I do, any time I assign something to the 
CorrelatedProxy, everything goes normally except that 'None' always becomes 
a key, assigned to the last value I assigned to the proxy. I tried 
debugging and tracing, but there's some quantum effect going on where if I 
inspect some value, some other value changes. I for the life of me can't 
figure out why it's doing this. I'm guessing it's some Instrumentation 
effect of SA, but I don't understand the in and outs of that very much. I 
currently can work around this by filtering out the None, but it'd be nice 
to know why this occurs and whether it will affect any other elements of my 
program with whatever is going on underneath.
    

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to