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 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 h...@urpla.net 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-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 Michael Bayer

On Aug 22, 2013, at 5:58 PM, Hans-Peter Jansen h...@urpla.net 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


[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.


Re: [sqlalchemy] Modification tracking

2013-08-21 Thread Michael Bayer

On Aug 21, 2013, at 12:40 PM, Hans-Peter Jansen h...@urpla.net 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