Re: [sqlalchemy] Modification tracking

2013-08-25 Thread Wolfgang Keller
> In an application, I have rather elaborate needs to track changes.

> Now I need to track all modifications to all fields, including the
> relationship list objects. 

One way to accomplish this would be within the database server itself.
With a rule that, instead of updating a record, inserts a new one (and
updates a "version" column). 

Sincerely,

Wolfgang

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Modification tracking

2013-08-22 Thread Michael Bayer

On Aug 22, 2013, at 5:58 PM, Hans-Peter Jansen  wrote:

> Dear Michael,
> 
> 
> Hmm, it looks like that needs to be applied on every column attribute..

> 
>> you can get a list of all attributes mapped using mapper.attrs:
>> http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html?highlight=mapp
>> er.attrs#sqlalchemy.orm.mapper.Mapper.attrs
> 
> from here. Since I need to track all 'net' changes, that's rather unpractical.

if you're just looking for "dirty" you can look at session.dirty itself, such 
as in a before_flush() handlernot sure what the specific scenario is.


> That is: just change instance attributes in place, and check for dirtiness 
> later on, with session.is_modified(obj, passive = True). I've chosen this 
> interface, because the fact of *really* being modified is essential here.
> 
> This scheme would do just fine, but doesn't work as expected.
> 
> See attached code. Depending on modification state of parent (line 51), the 
> modification state of the child is detected (parent changed) or not (parent 
> unchanged).

it looks like this code makes a change to p.children[0].name, and then expects 
that session.is_modified(p) would be True.is_modified() is per-object, so 
modifying Child means that just Child is modified, Parent hasn't changed at 
all.   If you want to make an "is_modified()" that recurses through object 
graphs, you'd need to traverse down yourself through related attributes.   I 
can show you what that looks like if this is what you want.

> In my real code, it's the other way around, modifications to relations are 
> detected (as I iterate through all of them), but changes to the "parent" 
> aren't, although the correct SQL UPDATE code is executed after commit(). 
> Since 
> it isn't detected correctly, my app falls flat on its nose..

well if you change Child.name, the only UPDATE needed is on the "child" table.  
the "parent" table doesn't require an UPDATE in this case which is why 
session.is_modified() returns False.


signature.asc
Description: Message signed with OpenPGP using GPGMail


Re: [sqlalchemy] Modification tracking

2013-08-22 Thread Hans-Peter Jansen
On Donnerstag, 22. August 2013 23:58:17 Hans-Peter Jansen wrote:
> Dear Michael,
> 
Pardon, I'm using 0.8.2 ATM.
> 
> Cheers,
> Pete

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.


Re: [sqlalchemy] Modification tracking

2013-08-22 Thread Hans-Peter Jansen
Dear Michael,

thanks for the detailed response.

On Mittwoch, 21. August 2013 16:55:18 Michael Bayer wrote:
> On Aug 21, 2013, at 12:40 PM, Hans-Peter Jansen  wrote:
> > Hi,
> > 
> > being new to SQLAlchemy, I try to get my way through it.
> > 
> > In an application, I have rather elaborate needs to track changes.
> > 
> > I've defined 3 classes with declarative, where the main class has
> > relationships with two auxiliary classes, that refer to the main class
> > with foreign references. All pretty basic stuff.
> > 
> > Now I need to track all modifications to all fields, including the
> > relationship list objects.
> > 
> > What is the best way to accomplish this task with SQLAlchemy?
> > 
> > Is there some boilerplate available to support this, or do I have to carry
> > around two objects and compare them item by item?
> you can intercept changes on attributes using the attribute event system: 
> http://docs.sqlalchemy.org/en/rel_0_8/orm/events.html#attribute-events
> 
> otherwise you can get at the changes on an attribute after the fact (but
> before a flush) using the history interface:
> http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html?highlight=history#sq
> lalchemy.orm.attributes.History

Hmm, it looks like that needs to be applied on every column attribute..

> you can get a list of all attributes mapped using mapper.attrs:
> http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html?highlight=mapp
> er.attrs#sqlalchemy.orm.mapper.Mapper.attrs

from here. Since I need to track all 'net' changes, that's rather unpractical.

I've changed my code to cope with best practices hopefully (from what I can 
extract from the overwhelming docs).

That is: just change instance attributes in place, and check for dirtiness 
later on, with session.is_modified(obj, passive = True). I've chosen this 
interface, because the fact of *really* being modified is essential here.

This scheme would do just fine, but doesn't work as expected.

See attached code. Depending on modification state of parent (line 51), the 
modification state of the child is detected (parent changed) or not (parent 
unchanged).

In my real code, it's the other way around, modifications to relations are 
detected (as I iterate through all of them), but changes to the "parent" 
aren't, although the correct SQL UPDATE code is executed after commit(). Since 
it isn't detected correctly, my app falls flat on its nose..

Do you have any idea on this one?

Cheers,
Pete

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.
from sqlalchemy import Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import relationship, backref, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

ERR = 1

class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable = False, index = True)
children = relationship('Child', backref = 'parent',
single_parent = True, # lazy = 'joined',
cascade = 'all, delete-orphan')


def __repr__(self):
cl = [repr(c) for c in self.children]
return 'Parent(%r, children: %s)' % (self.name, ', '.join(cl))

class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable = False, index = True)
parent_id = Column(Integer, ForeignKey('parent.id'), nullable = False)

def __repr__(self):
return 'Child(%r)' % (self.name)

if __name__ == '__main__':
engine = create_engine('sqlite://', echo = True)
Base.metadata.create_all(engine)
session = sessionmaker(engine, expire_on_commit=False)()

def pr(obj, exp, msg):
res = session.is_modified(obj, passive = True)
print msg + ',', 'expected: %s,' % exp, 'outcome: %s,' % res, exp == res and 'okay' or 'FAILED'

p = Parent(name = 'pa')
c1 = Child(name = 'li')
p.children.append(c1)

print 'Starting with:', p

session.add(p)
session.commit()

pr(p, False, 'initial session committed')

if ERR:
pr(p, False, 'parent not renamed')
else:
p.name = 'po'
pr(p, True, 'parent renamed to "po"')

c1.name = 'lo'
pr(c1, True, 'child renamed to "lo", testing child')
pr(p, True, 'child renamed to "lo", testing parent')

session.commit()




Re: [sqlalchemy] Modification tracking

2013-08-21 Thread Michael Bayer

On Aug 21, 2013, at 12:40 PM, Hans-Peter Jansen  wrote:

> Hi,
>  
> being new to SQLAlchemy, I try to get my way through it.
>  
> In an application, I have rather elaborate needs to track changes.
>  
> I've defined 3 classes with declarative, where the main class has 
> relationships with two auxiliary classes, that refer to the main class with 
> foreign references. All pretty basic stuff.
>  
> Now I need to track all modifications to all fields, including the 
> relationship list objects. 
>  
> What is the best way to accomplish this task with SQLAlchemy?
>  
> Is there some boilerplate available to support this, or do I have to carry 
> around two objects and compare them item by item?

you can intercept changes on attributes using the attribute event system:  
http://docs.sqlalchemy.org/en/rel_0_8/orm/events.html#attribute-events

otherwise you can get at the changes on an attribute after the fact (but before 
a flush) using the history interface: 
http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html?highlight=history#sqlalchemy.orm.attributes.History

you can get a list of all attributes mapped using mapper.attrs: 
http://docs.sqlalchemy.org/en/rel_0_8/orm/mapper_config.html?highlight=mapper.attrs#sqlalchemy.orm.mapper.Mapper.attrs




signature.asc
Description: Message signed with OpenPGP using GPGMail


[sqlalchemy] Modification tracking

2013-08-21 Thread Hans-Peter Jansen
Hi,

being new to SQLAlchemy, I try to get my way through it.

In an application, I have rather elaborate needs to track changes.

I've defined 3 classes with declarative, where the main class has relationships 
with two 
auxiliary classes, that refer to the main class with foreign references. All 
pretty basic 
stuff.

Now I need to track all modifications to all fields, including the relationship 
list objects. 

What is the best way to accomplish this task with SQLAlchemy?

Is there some boilerplate available to support this, or do I have to carry 
around two 
objects and compare them item by item?

TIA,
Pete

-- 
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.