{"id":4268,"library":"sqlalchemy-json","title":"SQLAlchemy JSON","description":"SQLAlchemy-JSON provides mutation-tracked JSON types to SQLAlchemy. It includes `MutableJson` for tracking top-level changes in JSON objects and `NestedMutableJson` for deep tracking within nested objects or lists. The library is actively maintained with recent releases focusing on Python 3 compatibility and enhanced functionality.","status":"active","version":"0.7.0","language":"en","source_language":"en","source_url":"https://github.com/edelooff/sqlalchemy-json","tags":["SQLAlchemy","JSON","ORM","Mutation Tracking"],"install":[{"cmd":"pip install sqlalchemy-json","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Core ORM and database toolkit dependency.","package":"SQLAlchemy","optional":false}],"imports":[{"symbol":"MutableJson","correct":"from sqlalchemy_json import MutableJson"},{"symbol":"NestedMutableJson","correct":"from sqlalchemy_json import NestedMutableJson"},{"note":"The class `JsonObject` was renamed to `MutableJson` in a backwards-incompatible change prior to PyPI release `0.2.0` (which established the current class names).","wrong":"from sqlalchemy_json import JsonObject","symbol":"JsonObject","correct":"from sqlalchemy_json import MutableJson"},{"note":"The class `NestedJsonObject` was renamed to `NestedMutableJson` in a backwards-incompatible change prior to PyPI release `0.2.0`.","wrong":"from sqlalchemy_json import NestedJsonObject","symbol":"NestedJsonObject","correct":"from sqlalchemy_json import NestedMutableJson"}],"quickstart":{"code":"import os\nfrom datetime import datetime\nfrom sqlalchemy import create_engine, Column, Text, ForeignKey, Integer, DateTime\nfrom sqlalchemy.orm import declarative_base, sessionmaker, Mapped, mapped_column\nfrom sqlalchemy_json import MutableJson, NestedMutableJson\n\n# Setup database (in-memory SQLite for example)\nDATABASE_URL = os.environ.get('DATABASE_URL', 'sqlite:///:memory:')\nengine = create_engine(DATABASE_URL, echo=True)\nSession = sessionmaker(bind=engine)\nBase = declarative_base()\n\n# Define models\nclass Author(Base):\n    __tablename__ = \"authors\"\n    id: Mapped[int] = mapped_column(Integer, primary_key=True)\n    name: Mapped[str] = mapped_column(Text)\n    # MutableJson for top-level changes\n    handles: Mapped[dict] = mapped_column(MutableJson)\n\nclass Article(Base):\n    __tablename__ = \"articles\"\n    id: Mapped[int] = mapped_column(Integer, primary_key=True)\n    author_id: Mapped[int] = mapped_column(ForeignKey('authors.id'))\n    content: Mapped[str] = mapped_column(Text)\n    # NestedMutableJson for deep changes\n    references: Mapped[dict] = mapped_column(NestedMutableJson)\n\n# Create tables\nBase.metadata.create_all(engine)\n\nsession = Session()\n\n# Example for MutableJson\nauthor = Author(name='John Doe', handles={'twitter': '@JohnDoe', 'facebook': 'JohnDoe'})\nsession.add(author)\nsession.commit()\n\n# Retrieve and modify top-level JSON\nretrieved_author = session.query(Author).first()\nprint(f\"Original handles: {retrieved_author.handles}\")\nretrieved_author.handles['twitter'] = '@JDoe'\nsession.commit() # Change is detected\nprint(f\"Updated handles (MutableJson): {retrieved_author.handles}\")\n\n# Example for NestedMutableJson\narticle = Article(\n    author_id=retrieved_author.id,\n    content='Some article content',\n    references={'github.com': {'repo1': 4, 'repo2': 7}, 'example.com': {'link1': 2}}\n)\nsession.add(article)\nsession.commit()\n\n# Retrieve and modify nested JSON\nretrieved_article = session.query(Article).first()\nprint(f\"Original references: {retrieved_article.references}\")\nretrieved_article.references['github.com']['repo1'] += 10 # Nested change\nsession.commit() # Change is detected\nprint(f\"Updated references (NestedMutableJson): {retrieved_article.references}\")\n\nsession.close()\n","lang":"python","description":"This quickstart demonstrates defining SQLAlchemy models with `MutableJson` for top-level mutable JSON fields and `NestedMutableJson` for fields requiring deep mutation tracking. It shows how changes to the JSON data are automatically detected and persisted to the database upon session commit."},"warnings":[{"fix":"Upgrade to Python 3 or pin `sqlalchemy-json` to `<0.6.0`.","message":"Python 2.x support was officially dropped in version `0.6.0`. Projects running on Python 2 must use an older version of `sqlalchemy-json` or upgrade to Python 3.","severity":"breaking","affected_versions":">=0.6.0"},{"fix":"Update imports to use `from sqlalchemy_json import MutableJson` and `from sqlalchemy_json import NestedMutableJson`.","message":"The primary public API classes `JsonObject` and `NestedJsonObject` were renamed to `MutableJson` and `NestedMutableJson` respectively in a breaking change prior to PyPI release `0.2.0`. Older codebases might still reference the deprecated names.","severity":"breaking","affected_versions":"<0.2.0 (effectively all PyPI releases)"},{"fix":"For deep mutation tracking (changes within nested JSON objects or arrays), use `NestedMutableJson` instead of `MutableJson`.","message":"`MutableJson` only tracks changes to the top-level dictionary or list (e.g., adding/removing keys, reassigning a key). It will NOT detect in-place modifications to nested dictionaries or lists within the JSON structure.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always use `MutableJson` or `NestedMutableJson` (or `mutable_json_type` factory) from `sqlalchemy_json` if mutation tracking is required. Do not rely on plain `sqlalchemy.JSON` for this behavior.","message":"SQLAlchemy's native `JSON` type (or `sqlalchemy.dialects.postgresql.JSONB`) does not automatically track in-place mutations to Python `dict` or `list` objects. `sqlalchemy-json` is specifically designed to add this mutation tracking capability.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Upgrade to version `0.6.0` or later to ensure proper pickling support.","message":"Earlier versions (prior to `0.6.0` and `0.5.0`) contained bugs related to pickling support, which could lead to unexpected behavior or data corruption if models with JSON types were pickled.","severity":"gotcha","affected_versions":"<0.6.0"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}