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 [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.