assocaition proxy support for scalar-targeted attributes
Issue #2751
resolved
from sqlalchemy.engine import create_engine
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative.api import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.schema import Column, ForeignKey
from sqlalchemy.types import Integer, String
Base = declarative_base()
class A(Base):
__tablename__ = 'table_a'
id = Column(Integer, primary_key=True)
color = Column(String)
def __init__(self, color):
self.color = color
class B(Base):
__tablename__ = 'table_b'
id = Column(Integer, primary_key=True)
a_id = Column(Integer, ForeignKey('table_a.id'))
a_re = relationship('A', backref='b_re')
a_color = association_proxy('a_re', 'color')
if __name__ == '__main__':
engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(engine)
session = Session()
Base.metadata.create_all(engine)
b1 = B()
b2 = B()
b3 = B()
b4 = B()
b1.a_color = 'blue'
b2.a_re = A(color=None)
session.add_all([b2, b3, b4](b1,))
q = session.query(B).filter(B.a_color == None).all()
p = session.query(B).filter(B.a_color != None).all()
v = session.query(B).filter(B.a_color == 'blue').all()
z = session.query(B).filter(B.a_color != 'blue').all()
from sqlalchemy import __version__
if __version__ >= "0.9.0":
assert v == [b1](b1)
assert q == [b3](b2,)
assert p == [b4](b1,)
assert z == [b4](b4)
# will also add a special feature for this
r = session.query(B).filter(B.a_color.has()).all()
assert r == [b2, b4](b1,)
# will also add a special feature for this
w = session.query(B).filter(~B.a_color.has()).all()
assert w == [b3](b3)
# this is the equivalent of 0.8's B.a_color != None
s = session.query(B).filter(
or_(B.a_color != None,
~B.a_color.has())
).all()
assert s == [b3, b4](b1,)
# the equivalent of 0.8's B.a_color != 'blue'
t = session.query(B).filter(
or_(
B.a_color != 'blue',
B.a_color == None
)
).all()
assert t == [b3, b4](b2,)
else:
assert v == [b1](b1)
assert q == [b2](b2)
assert p == [b3, b4](b1,)
assert z == [b3, b4](b2,)
this involves a behavioral change even to non-scalar association proxies, unless we special case it. If we have Parent.m2o_something.m2o_otherthing / Parent.other, the meaning of Parent.other == None
normally includes just Parent.m2o_something.has(m2o_otherthing=None)
- this adds in ~Parent.m2o_something.has()
.
As the example illustrates, this totally changes return results so there's a very high chance applications are relying on the current behavior, and am leaning towards an 0.9 only here.
Comments (6)
-
reporter -
reporter - changed status to resolved
this change is in 20d1e9c3fa8ccc992079.
-
reporter - changed status to open
- removed status
this needs a full description in the migration guide, leaving this open as a TODO.
-
reporter -
reporter - changed status to resolved
-
reporter - removed milestone
Removing milestone: 0.9.0 (automated comment)
- Log in to comment