SQLAlchemy-Continuum

1.6.0 · active · verified Sun Apr 12

SQLAlchemy-Continuum is a versioning and auditing extension for SQLAlchemy. It automatically creates versions for inserts, deletes, and updates of SQLAlchemy models, supports Alembic migrations, and allows reverting objects and their relations to previous states. The current version, 1.6.0, was released in January 2026, indicating an active development and maintenance cadence with recent updates for Python 3.13/3.14 and SQLAlchemy 2.0 compatibility.

Warnings

Install

Imports

Quickstart

This quickstart demonstrates how to enable versioning for a SQLAlchemy model. It involves calling `make_versioned()` before model definitions, adding `__versioned__ = {}` to desired models, and then calling `configure_mappers()` after all models are defined. It then shows how to create, update, and retrieve historical versions of an object, including reverting to a previous state.

import sqlalchemy as sa
from sqlalchemy import create_engine, Column, Integer, Unicode, UnicodeText
from sqlalchemy.orm import sessionmaker, declarative_base, configure_mappers
from sqlalchemy_continuum import make_versioned, version_class

# Call make_versioned() before defining models
make_versioned(user_cls=None)

Base = declarative_base()

class Article(Base):
    __tablename__ = 'article'
    __versioned__ = {}
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(Unicode(255))
    content = Column(UnicodeText)

    def __repr__(self):
        return f"Article(id={self.id}, name='{self.name}')"

# After defining all models, call configure_mappers
configure_mappers()

# Setup database and session
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

# Create an article
article = Article(name='Initial Name', content='Initial Content')
session.add(article)
session.commit()
print(f"Created: {article}")

# Update the article
article.name = 'Updated Name'
session.commit()
print(f"Updated: {article}")

# Access versions
ArticleVersion = version_class(Article)
versions = session.query(ArticleVersion).filter_by(id=article.id).order_by(ArticleVersion.transaction_id).all()

print(f"\nAll versions for Article {article.id}:")
for v in versions:
    print(f"- Version (tx_id={v.transaction_id}): name='{v.name}'")

# Revert to the first version
if versions:
    first_version = versions[0]
    first_version.revert()
    session.commit()
    print(f"\nReverted to first version. Current article name: {article.name}")

session.close()

view raw JSON →