From b56ed8ccb84fb4e173930696ed052acdff5cc3ad Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 14 Oct 2007 18:06:13 +0000 Subject: [PATCH] - backref remove object operation doesn't fail if the other-side collection doesn't contain the item, supports noload collections [ticket:813] --- CHANGES | 4 ++++ lib/sqlalchemy/orm/attributes.py | 8 +++++++- test/orm/unitofwork.py | 25 +++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 53ce0e75ee..7f1543e868 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,10 @@ CHANGES - Added partial index support for PostgreSQL. Use the postgres_where keyword on the Index. +- backref remove object operation doesn't fail if the other-side + collection doesn't contain the item, supports noload collections + [ticket:813] + - The IdentifierPreprarer's _requires_quotes test is now regex based. Any out-of-tree dialects that provide custom sets of legal_characters or illegal_initial_characters will need to move to regexes or override diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 714b00376c..4b64d52e31 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -520,7 +520,13 @@ class GenericBackrefExtension(interfaces.AttributeExtension): if oldchild is child: return if oldchild is not None: - getattr(oldchild.__class__, self.key).impl.remove(oldchild._state, obj, initiator) + # With lazy=None, there's no guarantee that the full collection is + # present when updating via a backref. + impl = getattr(oldchild.__class__, self.key).impl + try: + impl.remove(oldchild._state, obj, initiator) + except (ValueError, KeyError, IndexError): + pass if child is not None: getattr(child.__class__, self.key).impl.append(child._state, obj, initiator) diff --git a/test/orm/unitofwork.py b/test/orm/unitofwork.py index dcf7581fe5..d1011068b6 100644 --- a/test/orm/unitofwork.py +++ b/test/orm/unitofwork.py @@ -1334,6 +1334,31 @@ class ManyToOneTest(ORMTest): u1 = Session.query(User).get(u1.user_id) u2 = Session.query(User).get(u2.user_id) assert a1.user is u2 + + def test_bidirectional_noload(self): + mapper(User, users, properties={ + 'addresses':relation(Address, backref='user', lazy=None) + }) + mapper(Address, addresses) + + sess = Session() + + # try it on unsaved objects + u1 = User() + a1 = Address() + a1.user = u1 + sess.save(u1) + sess.flush() + sess.clear() + + a1 = sess.query(Address).get(a1.address_id) + + a1.user = None + sess.flush() + sess.clear() + assert sess.query(Address).get(a1.address_id).user is None + assert sess.query(User).get(u1.user_id).addresses == [] + class ManyToManyTest(ORMTest): metadata = tables.metadata -- 2.47.3