Have a look at http://web2py.com/book/default/chapter/07#Record-Versioning


On May 6, 6:18 pm, nick name <i.like.privacy....@gmail.com> wrote:
> My use of web2py requires an audit trail for (essentially) all database
> tables; The preferable way to do that is to keep a "foo_history" table for
> each table "foo". The records (both audited and original) need to have a
> "revision" that increments with each update, and "last modified on", "last
> modified by" fields that get updated with the user_id and the time on each
> update.
>
> At this point in time, there is no need to delete records - but if there
> was, I'm not sure what the proper way would be -- possibly having another
> field "deleted" on the audit trail table, which would be set to "true" on
> the revision that was the latest version.
>
> Now, the built in Crud system gives me most of what I want (I don't see how
> to make it keep the history of the deleted table above, though for now
> that's not a problem). But there's quite a bit of application logic that
> needs this which cannot be implemented using the Crud.
>
> The "classic" solution is to write this as stored procedures. I would like
> to avoid that for portability and maintenance reasons. Another solution is
> to use my own "update/insert/delete" methods that update audit tables
> whenever a record updates. That's error prone, and I would rather avoid
> that, especially since I _do_ want to build on web2py infrastructure such as
> Crud for other things.
>
> The solution that I'm thinking of is to hook the DAL; specifically, the
> following functions would be sufficient for me; It seems that all database
> modifications go through them eventually, whether called directly or when
> manipulating Rows or Row objects.
>
> insert: (copy all newly added records to the audit table table - easy)
> update: (copy all modified records to the audit table, add a 'revision =
> revision + 1' to the SET code - easy)
> delete: (copy all deleted records to the audit table, adding a 'deleted =
> True' - possibly a little more complicated)
>
> For completeness, hooking "truncate" and "drop table" to do the same thing
> (either raise an error if that is disallowed, or transform it into a delete
> of each individual record so that everything goes into the audit). And I
> would also disable migrations if I do that, because they may change the
> database without updating my audit trail.
>
> Now, before I start working on a monkey patch (or full patch) to dal.py -
> perhaps I've missed a simpler way to do the same thing?
>
> If I haven't - I'm currently working with Postgres and SQLite; I would like
> to contribute the resulting patch to the web2py project, but have no time to
> evaluate and test on other databases/gae at the moment. Is there anything
> else I should be aware of that would be required for other databases?
>
> ====
>
> Finally, a question about transaction rollback - in my app, I sometimes want
> to rollback everything (as if I did e.g. raise
> MySecurityException("Forbidden")), but actually return a non-error HTML
> result to the user. I am aware of db.rollback(), but the exception handling
> code does more, e.g., today it does:
>
>  if response._custom_rollback:
>    response._custom_rollback()
>  else:
>    BaseAdapter.close_all_instances('rollback')
>
> I would suggest adding an "response._transaction_verb" variable, which would
> default to 'COMMIT', but could be changed to 'ROLLBACK', and would determine
> what to do with the database (commit/rollback) in the case of a successful
> completion - meaning raising of an HTTP exception or simple return from
> controller.
>
> On other exception, I would expect rollback always (and the application code
> can call db.commit or BaseAdapter.close_all_instances('commit') or whatever
> if needed) - because committing on error is something that has to be
> extremely explicit.
>
> What say you?

Reply via email to