{"id":14065378,"url":"https://github.com/corridor/sqlalchemy-history","last_synced_at":"2025-04-05T08:03:02.931Z","repository":{"id":60838035,"uuid":"545319568","full_name":"corridor/sqlalchemy-history","owner":"corridor","description":"Library to keep track of changes in SQLAlchemy.","archived":false,"fork":false,"pushed_at":"2024-10-01T09:31:24.000Z","size":3991,"stargazers_count":36,"open_issues_count":19,"forks_count":26,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T07:01:35.681Z","etag":null,"topics":["database","hactoberfest","mssql","mysql","oracle","postgresql","sqlalchemy","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"kvesteri/sqlalchemy-continuum","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/corridor.png","metadata":{"files":{"readme":"docs/README.md","changelog":"CHANGES.rst","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-04T06:47:02.000Z","updated_at":"2025-03-28T12:06:09.000Z","dependencies_parsed_at":"2023-11-07T00:14:44.621Z","dependency_job_id":"fec55aaa-bb38-40c6-aa69-ee103bf87323","html_url":"https://github.com/corridor/sqlalchemy-history","commit_stats":{"total_commits":738,"total_committers":49,"mean_commits":"15.061224489795919","dds":"0.25338753387533874","last_synced_commit":"cae1328a18040dbc1f16072b3a65799a4ea3581e"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corridor%2Fsqlalchemy-history","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corridor%2Fsqlalchemy-history/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corridor%2Fsqlalchemy-history/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corridor%2Fsqlalchemy-history/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/corridor","download_url":"https://codeload.github.com/corridor/sqlalchemy-history/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247305919,"owners_count":20917204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","hactoberfest","mssql","mysql","oracle","postgresql","sqlalchemy","sqlite"],"created_at":"2024-08-13T07:04:27.668Z","updated_at":"2025-04-05T08:03:02.896Z","avatar_url":"https://github.com/corridor.png","language":"Python","readme":"[![Coverage Status](https://coveralls.io/repos/github/corridor/sqlalchemy-history/badge.svg)](https://coveralls.io/github/corridor/sqlalchemy-history)\n\n# SQLAlchemy-History\n\nSQLAlchemy-history is a fork of sqlalchemy-continuum.\nAn auditing extension for sqlalchemy which keeps a track of the history of your sqlalchemy models\n\n## Features\n\n- Supports sqlalchemy 2+ and python 3.7+\n- Tracks history for inserts, deletes, and updates\n- Does not store updates which don't change anything\n- Supports alembic migrations\n- Can revert objects data as well as all object relations at given transaction even if the object was deleted\n- Transactions can be queried afterwards using SQLAlchemy query syntax\n- Query for changed records at given transaction\n- Temporal relationship reflection. Get the relationships of an object in that point in time.\n\n## QuickStart\n\n```sh\npip install sqlalchemy-history\n```\n\nIn order to make your models versioned you need two things:\n\n1. Call `make_versioned()` before your models are defined.\n2. Add `__versioned__` to all models you wish to add versioning to\n\n```python\n\u003e\u003e\u003e from sqlalchemy_history import make_versioned\n\u003e\u003e\u003e make_versioned(user_cls=None)\n\u003e\u003e\u003e class Article(Base):\n...    __versioned__ = {}\n...    __tablename__ = 'article'\n...    id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)\n...    name = sa.Column(sa.Unicode(255))\n...    content = sa.Column(sa.UnicodeText)\n\u003e\u003e\u003e article = Article(name='Some article', content='Some content')\n\u003e\u003e\u003e session.add(article)\n\u003e\u003e\u003e session.commit()\n'article has now one version stored in database'\n\u003e\u003e\u003e article.versions[0].name\n'Some article'\n\u003e\u003e\u003e article.name = 'Updated name'\n\u003e\u003e\u003e session.commit()\n\u003e\u003e\u003e article.versions[1].name\n'Updated name'\n\u003e\u003e\u003e article.versions[0].revert()\n'lets revert back to first version'\n\u003e\u003e\u003e article.name\n'Some article'\n```\n\nFor completeness, below is a working example.\n\n```python\nfrom sqlalchemy_history import make_versioned\nfrom sqlalchemy import Column, Integer, Unicode, UnicodeText, create_engine\nfrom sqlalchemy.orm import declarative_base\nfrom sqlalchemy.orm import create_session, configure_mappers\nmake_versioned(user_cls=None)\nBase = declarative_base()\nclass Article(Base):\n    __versioned__ = {}\n    __tablename__ = 'article'\n    id = Column(Integer, primary_key=True, autoincrement=True)\n    name = Column(Unicode(255))\n    content = Column(UnicodeText)\nconfigure_mappers()\nengine = create_engine('sqlite://')\nBase.metadata.create_all(engine)\nsession = create_session(bind=engine, autocommit=False)\narticle = Article(name='Some article', content='Some content')\nsession.add(article)\nsession.commit()\nprint(article.versions[0].name) # 'Some article'\narticle.name = 'Updated name'\nsession.commit()\nprint(article.versions[1].name) # 'Updated name'\narticle.versions[0].revert()\nprint(article.name) # 'Some article'\n```\n\n## Resources\n\n- [Documentation](https://corridor.github.io/sqlalchemy-history/)\n- [Issue Tracker](http://github.com/corridor/sqlalchemy-history/issues)\n- [Code](http://github.com/corridor/sqlalchemy-history/)\n\n## More information\n\n- [http://en.wikipedia.org/wiki/Slowly_changing_dimension](http://en.wikipedia.org/wiki/Slowly_changing_dimension)\n- [http://en.wikipedia.org/wiki/Change_data_capture](http://en.wikipedia.org/wiki/Change_data_capture)\n- [http://en.wikipedia.org/wiki/Anchor_Modeling](http://en.wikipedia.org/wiki/Anchor_Modeling)\n- [http://en.wikipedia.org/wiki/Shadow_table](http://en.wikipedia.org/wiki/Shadow_table)\n- [https://wiki.postgresql.org/wiki/Audit_trigger](https://wiki.postgresql.org/wiki/Audit_trigger)\n- [https://wiki.postgresql.org/wiki/Audit_trigger_91plus](https://wiki.postgresql.org/wiki/Audit_trigger_91plus)\n- [http://kosalads.blogspot.fi/2014/06/implement-audit-functionality-in.html](http://kosalads.blogspot.fi/2014/06/implement-audit-functionality-in.html)\n- [https://github.com/2ndQuadrant/pgaudit](https://github.com/2ndQuadrant/pgaudit)\n\n## Comparison\n\nPrimary reasons to create another library:\n\n- Be future looking and support sqlalchemy 2.x\n- Support multiple databases (sqlite, mysql, postgres, mssql, oracle)\n- Focus on the history tracking and be as efficient as possible when doing it\n\nWe found multiple libraries which has an implementation of history tracking:\n\n1. [sqlalchemy-continuum](https://github.com/kvesteri/sqlalchemy-continuum)\n    - Does not support oracle, mssql\n    - Feature filled making it difficult to maintain all plugins/extensions\n2. [flask-continuum](https://github.com/bprinty/flask-continuum)\n    - Thin wrapper on sqlalchemy-continuum specifically for flask\n3. [postgresql-audit](https://github.com/kvesteri/postgresql-audit)\n    - Supports only postgres\n4. [versionalchemy](https://github.com/NerdWalletOSS/versionalchemy)\n    - Not updated in a while\n    - No reverting capability, Relationship queries on history not available\n5. [django-simple-history](https://github.com/jazzband/django-simple-history)\n    - Uses django ORM, does not support sqlalchemy\n6. [sqlalchemy example versioning-objects](http://docs.sqlalchemy.org/en/latest/orm/examples.html#versioning-objects)\n    - Simple example to demonstrate implementation - but very minimal\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorridor%2Fsqlalchemy-history","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcorridor%2Fsqlalchemy-history","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorridor%2Fsqlalchemy-history/lists"}