I think I may have found the issue.  If I modify your example so that 
"C.k1" is a declared_attr, the assertion on the second C instance loads the 
(100,1000) record from table "ab" again.  I originally had my "k1" in a 
mixin, but it looks like the mixin isn't involved, and it is purely the 
declared_attr.  I assume that the "k1" coming from the declared_attr 
doesn't have quite the right karma in some way when used in the 
ForeignKeyConstraint in C that makes the relationship to AB?  I'll have to 
go back and dig into the docs, but am I using declared_attr decorator 
improperly, or is there a better way to refer to "k1" in the 
ForeignKeyConstraint?  

My modified version of your test is below.  Change the "useDeclared" 
variable to False to bypass the declared_attr behaviour and recover the 
working of the original test.

from sqlalchemy import * 
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import declarative_base, declared_attr 

useDeclared = True # set True to see unneeded select on #2
useMixin = False # put the declared in the mixin if True

Base = declarative_base() 

class A(Base): 
     __tablename__ = 'a' 
     id = Column(Integer, primary_key=True) 

     assoc = relationship("AB") 

class B(Base): 
     __tablename__ = 'b' 
     id = Column(Integer, primary_key=True) 


class AB(Base): 
     __tablename__ = 'ab' 

     a_id = Column(ForeignKey('a.id'), primary_key=True) 
     b_id = Column(ForeignKey('b.id'), primary_key=True) 

     a = relationship("A") 
     b = relationship("B") 

class Mixin_C(object):
if useMixin:
@declared_attr
def k1(cls):
print "DECLARED K1"
return Column(Integer)

class C(Base, Mixin_C): 
     __tablename__ = 'c' 

     id = Column(Integer, primary_key=True) 
     if not useMixin:
    if useDeclared:
    @declared_attr
    def k1(cls):
    print "declared without mixin"
    return Column(Integer)
    else:
    print "INLINE k1"
    k1 = Column(Integer)
     k2 = Column(Integer) 
     assoc = relationship("AB") 

     __table_args__ = ( 
         ForeignKeyConstraint(['k1', 'k2'], ['ab.a_id', 'ab.b_id']), {}) 

e = create_engine("sqlite://", echo=True) 
Base.metadata.create_all(e) 

s = Session(e) 
a, b = A(id=100), B(id=1000) 

ab = AB(a=a, b=b) 

c1 = C(id=1, assoc=ab) 
c2 = C(id=2, assoc=ab) 
s.add_all([a, b, ab, c1, c2]) 
s.commit() 
s.close()  # clears everything 

c1 = s.query(C).get(1) 

print "#1 EMITS LAZYLOAD:" 
assoc = c1.assoc  # note we keep a strong reference here 

c2 = s.query(C).get(2) 

print "\n#2 SHOULD NOT EMIT LAZYLOAD%s"%("" if not useDeclared else ", but 
will because of declared_attr")
assert c2.assoc is assoc 

-- 
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 https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to