On Jun 7, 2011, at 1:23 PM, Sebastian Elsner wrote:

> Hello,
> 
> using Python 2.6 and SA 0.6.6. Please see the example below. I want to get 
> the History of a relationship attribute, but whatever I pass to the "passive" 
> argument, I never get the "deleted version" of the object, only the 
> PASSIVE_NO_RESULT symbol (if I understand correctly, I would not need to pass 
> anything). Where is the error in my reasoning with this?

The short answer is set active_history=True on the relationship().

Its a subtlety in how the tracking works.  History works by moving the previous 
value of an attribute aside and establishing the new one as current.   In your 
test, "a.user" is expired, the __dict__ is empty - a similar condition as when 
the object is first loaded.  History tracking for many-to-one, for the purposes 
of the unit of work, doesn't need to know the previous value.   So for the 
prevailing use case, that people want to be able to set "a.user = <new user>" 
without an entirely needless SELECT occurring, the default is that no SELECT is 
emitted.

If you were to load the attribute beforehand:

        u2 = User("jack")
        a.user
        a.user = u2

        print get_history(a, "user")

you'd see it.

Otherwise setting active_history=True will load it when it changes, you'd just 
see that SELECT statement occurring if the value weren't loaded already.

There's no option right now to load the "old" value only on the history grab.   
  It would add a lot of complexity and there hasn't been a need for it.







> 
> Cheers
> 
> Sebastian
> 
> from sqlalchemy.ext.declarative import declarative_base
> from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
> from sqlalchemy.orm import sessionmaker, relationship
> from sqlalchemy.orm.attributes import get_history
> 
> Base = declarative_base()
> engine = create_engine('sqlite:///:memory:')
> Base.metadata.bind = engine
> Session = sessionmaker(bind = engine)
> 
> class User(Base):
>    __tablename__ = 'users'
> 
>    id = Column(Integer, primary_key = True)
>    name = Column(String)
> 
>    def __init__(self, name):
>        self.name = name
> 
>    def __repr__(self):
>        return "<User('%s')>" % (self.name)
> 
> class Address(Base):
> 
>    __tablename__ = "addresses"
> 
>    id = Column(Integer, primary_key = True)
>    user_id = Column(Integer, ForeignKey('users.id'))
>    user = relationship('User', backref = 'addresses')
>    street = Column(String)
> 
>    def __init__(self, street):
>        self.street = street
> 
>    def __repr__(self):
>        return "<Address('%s')>" % (self.street)
> 
> Base.metadata.create_all(engine)
> session = Session()
> 
> u = User("joe")
> a = Address("Downing Street")
> u.addresses.append(a)
> session.add(u)
> 
> session.commit()
> 
> u2 = User("jack")
> a.user = u2
> 
> print get_history(a, "user")
> #([<User('jack')>], (), [<symbol 'PASSIVE_NO_RESULT>])
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> To unsubscribe from this group, send email to 
> sqlalchemy+unsubscr...@googlegroups.com.
> For more options, visit this group at 
> http://groups.google.com/group/sqlalchemy?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to