honor passive on scalar backref assignment
Issue #1483
resolved
patch:
Index: lib/sqlalchemy/orm/dynamic.py
===================================================================
--- lib/sqlalchemy/orm/dynamic.py (revision 6172)
+++ lib/sqlalchemy/orm/dynamic.py (working copy)
@@ -100,7 +100,7 @@
dict_[self.key](self.key) = True
return state.committed_state[self.key](self.key)
- def set(self, state, dict_, value, initiator):
+ def set(self, state, dict_, value, initiator, passive=attributes.PASSIVE_OFF):
if initiator is self:
return
Index: lib/sqlalchemy/orm/attributes.py
===================================================================
--- lib/sqlalchemy/orm/attributes.py (revision 6172)
+++ lib/sqlalchemy/orm/attributes.py (working copy)
@@ -383,12 +383,12 @@
return self.initialize(state, dict_)
def append(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
- self.set(state, dict_, value, initiator)
+ self.set(state, dict_, value, initiator, passive=passive)
def remove(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
- self.set(state, dict_, None, initiator)
+ self.set(state, dict_, None, initiator, passive=passive)
- def set(self, state, dict_, value, initiator):
+ def set(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
raise NotImplementedError()
def get_committed_value(self, state, dict_, passive=PASSIVE_OFF):
@@ -436,7 +436,7 @@
return History.from_attribute(
self, state, dict_.get(self.key, NO_VALUE))
- def set(self, state, dict_, value, initiator):
+ def set(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
if initiator is self:
return
@@ -511,7 +511,7 @@
ScalarAttributeImpl.delete(self, state, dict_)
state.mutable_dict.pop(self.key)
- def set(self, state, dict_, value, initiator):
+ def set(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
if initiator is self:
return
@@ -559,7 +559,7 @@
else:
return History.from_attribute(self, state, current)
- def set(self, state, dict_, value, initiator):
+ def set(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
"""Set a value on the given InstanceState.
`initiator` is the ``InstrumentedAttribute`` that initiated the
@@ -570,8 +570,10 @@
if initiator is self:
return
- # may want to add options to allow the get() here to be passive
- old = self.get(state, dict_)
+ old = self.get(state, dict_, passive=passive)
+ if old is PASSIVE_NORESULT:
+ old = None
+
value = self.fire_replace_event(state, dict_, value, old, initiator)
dict_[self.key](self.key) = value
@@ -707,7 +709,7 @@
else:
collection.remove_with_event(value, initiator)
- def set(self, state, dict_, value, initiator):
+ def set(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
"""Set a value on the given object.
`initiator` is the ``InstrumentedAttribute`` that initiated the
here is a test for the common case, throws the usual orphan error without the patch:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
site = relation("Site", uselist=False, cascade="all, delete-orphan", backref="user")
class Site(Base):
__tablename__ = 'site'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('user.id'))
title = Column(String)
engine = create_engine('sqlite://', echo=True)
Base.metadata.create_all(engine)
sess = sessionmaker(bind=engine)()
v = User(name='victor')
sess.add(v)
sess.commit()
print "---------------"
s = Site(title='asdf')
sess.add(s)
s.user = v
sess.commit()
however, need to ensure things go well for every combination of forwards/backwards ref here. Also is None
the most appropriate thing to be using here (i.e. not NO_VALUE, etc.)
Comments (3)
-
reporter -
reporter - changed status to resolved
took a pretty cautious approach to this and takes out a certain class of unnecessary lazy loads. the above test case is one-to-one on the non-fk side though, so it still loses. 306c901946da9b06e79171c167a454cf0550b11d
-
reporter - removed milestone
Removing milestone: 0.5.6 (automated comment)
- Log in to comment
particularly, if you did the really rare thing of setting up a one-to-many based on an association table, then moved an item from one "many" collection to another. does the old behavior result in the association table being updated due to the backref ? if so then this results in backwards incompatible behavior (again very rare).