Re: [sqlalchemy] Modification tracking
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
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
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
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
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
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