On Wed, Jan 31, 2018 at 5:27 PM, Stanislav Lobanov <n10101...@gmail.com> wrote: > Hello, i need to create a system, that can store historical versions of > objects. > > Example model looks like: > > class User(Base): > id=Column(Integer) # ForeignKey > start=Column(DateTime) > end=Column(DateTime) > name=Column(String) > > I have implemented .add_new() and .save() methods on base class, which > performs custom logic on inserting rows into database. > > .add_new() method just assigns next id, default start and end date values > (start=datetime.now() and end=None). > > Rows where start has value and end is null are considered "live" rows, all > other rows are considered as "historical" > > .save() method changes current record dates (end date becomes current > moment, so this version is considered as "historical", because it has start > and end date lifetime moments set). Also, it performs some custom logic on > determining if new version of record should be created — it should not be > created, if name is not chaged. > > Example: > > user = User(name='User1') > user.add_new() > # user has values: id=1, start=<current datetime>, end=None, name='User1' > > user.name='test2' > user.save() > # user has values: id=1, start=<previous start>, end=<current datetime>, > name='test2' > > user.name='test2' > user.save() > # user has values: id=1, start=<previous start>, end=<current datetime>, > name='test2' and no insert performed, because name is not changed. > > > > This methods look for me inconsistent and error prone, so i want to be able > to use session.add() method. > > Are there any possibility to add support for custom process of saving and > modifying objects by using default sqlalchemy's apis? > > P.S.: in current example, table has composite pk (id, start, end), so id is > not auto incremented when inserting new row. Also, in such scenario we can > not have ForeignKey constraint. >
The SQLAlchemy documentation has some examples of a couple of different ways of doing this: http://docs.sqlalchemy.org/en/latest/orm/examples.html#versioning-objects The history_meta.py example creates separate "history" tables for each table that you want to be versioned. Whenever you UPDATE a versioned object, a new row gets INSERTed into the history table. The versioned_rows.py example is more like what you described, converting what would have been an UPDATE into an INSERT on the same table. Both examples use the "before_flush" session event to implement the versioning, so other parts of your code don't need to be aware of it. Hope that helps, Simon -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- 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 https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.