On Oct 24, 2013, at 4:40 PM, Daniel Grace <thisgenericn...@gmail.com> wrote:
> The problem I was encountering is that history doesn't make it easy to > differentiate between collections and non-collections very well: > > inspect(obj).attrs.intcolumn.history.unchanged returns return [intval], > rather than intval. > > inspect(obj).attrs.children.history.unchanged returns [<childobj>] the rationale for this is because the history API was first and foremost designed for internals, where it iterates through these collections without regard for whether the collection is a many-to-one or one-to-many. If you want to distinguish between scalars and collections, this could be added to attribute state directly but for now you can look at state.manager[key].collection, which is a boolean. > > It'd be handy if I can just do something like: > > original = get_original(self) > if original.value != self.value: > pass history.has_changes() tells you the equivalent of if the “old” and “new” values are different. > With some sufficiently-robust-but-should-be-simple implementation of > get_history. there’s many “simple” implementations that wouldn’t do what everyone needs - the API you want might not accomplish what someone else wants - which means if we rush ahead and implement a “simple” API that doesn’t take enough use cases into account, we get two apis instead of one, and new users will still want more APIs - this is how confusing and inconsistent APIs are produced, e.g. piecemeal in response to individual requests, rather than designing for a bigger picture. The existing API is actually the “simple-yet-robust” implementation for what this system was originally designed for. Once I have dozens of people asking me for the same thing, or different things for which I can discern exactly what everyone really needs (e.g. when the “big picture” is very clear), then the “simple” API becomes apparent. We’re not there yet, sorry. We’re only at the “it’s possible” phase on attribute history. > The main problem with Jonathan's approach is the results will be inconsistent > if any of the attributes are collections. well his approach is iterating through the table’s columns, which is of limited use. The loop I illustrated iterates through all mapped attributes including collections which takes more into account. If you care to illustrate a function with clear inputs and outputs, I can work up whatever kind of implementation it needs internally for you, or at least point out those areas where more design is needed (such as how to generate “diffs” of collections). > > Michael: By "Losing changes", I mean that I know it's easily possible to get > to the unmodified version of an object via session.rollback() or > session.expire() -- but then I lose the pending (not yet committed) changes > that I'm trying to compare against. I wasn't referring to auto flush. Well if you are looking to actually re-construct the entire object graph from memory as it was before the flush, this is something I looked into with great detail some years ago and determined it would be enormously complex to do completely - it is of course simple for scalar attributes but once you start dealing with collections and bidirectional connections between objects, reproducing the full state of objects prior to user and within-flush manipulation of state becomes a major task, which also leans towards adding a lot more overhead to the history tracking system in the first place which starts to degrade performance even further than the instrumentation already does. If you want to maintain your own “diff” of changes as they are produced, which is entirely independent of flush(), you can do this - just implement attribute event listening for all attributes, where you’ll be able to log every change to an object graph into the format that you need. This is not trivial but you’d have full control over things. Instrumentation for all attributes is illustrated in the examples/custom_attributes/listen_for_events.py example. -- 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.