How to store JSON data in SQLAlchemy

Updated: January 3, 2024 By: Guest Contributor Post a comment

Introduction

With the wide adoption of JSON as a medium for data interchange, there is a growing need to persist JSON data efficiently. This tutorial explains how you can store JSON data within a relational database using SQLAlchemy, a popular ORM for Python.

Before proceeding, make sure you have Python installed on your system along with SQLAlchemy and a database like PostgreSQL that supports JSON data types. Basic knowledge of Python and SQL is also needed.

Defining a Model with a JSON Column

SQLAlchemy allows you to define models with JSON type columns that can store JSON structures directly:

from sqlalchemy import create_engine, Column, Integer, JSONrom sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class DataStore(Base):
    __tablename__ = 'data_store'
    id = Column(Integer, primary_key=True)
    data = Column(JSON)

engine = create_engine('sqlite:///your-database.db')
Base.metadata.create_all(engine)

After creating the model, you can insert JSON data like a regular Python dictionary:

from sqlalchemy.orm import sessionmaker

Session = sessionmaker(bind=engine)
session = Session()

new_json_data = DataStore(data={'key': 'value'})
session.add(new_json_data)
session.commit()

Querying JSON data

Retrieving JSON data is straightforward and works like querying any other field:

stored_json = session.query(DataStore).filter_by(id=1).first()
print(stored_json.data)

JSON querying capabilities can be expanded if you’re using a database system like PostgreSQL that supports advanced JSON functions.

Advanced Querying with PostgreSQL

For databases that support advanced JSON operations, you can apply filters and searches directly within the JSON column.

from sqlalchemy.dialects.postgresql import JSONB

#... other model definitions

class PostgreSQLDataStore(Base):
    __tablename__ = 'pg_data_store'
    id = Column(Integer, primary_key=True)
    data = Column(JSONB)

# ... Boilerplate for creating session

results = session.query(PostgreSQLDataStore).filter(PostgreSQLDataStore.data['key'].astext == 'value').all()
for result in results:
    print(result.data)

Working with JSON Arrays

You can also store JSON arrays in a JSON column and perform operations like appending new elements, or querying specific ones.

my_json_data = session.query(DataStore).filter_by(id=1).first()

# Append to JSON array
my_json_data.data['array_key'].append('new_value')
session.commit()

Schema Migrations

To accommodate changes in your JSON-based models, you can use migration tools like Alembic to manage your database schema:

# Install Alembic via pip
pip install alembic

# Initialize Alembic in your project
alembic init migrations

# Modify Alembic's env.py to include your models

# Generate a new migration
alembic revision --autogenerate -m 'Added JSON column'

# Apply the migration to the database
alembic upgrade head

Handling Serialization and Deserialization

SQLAlchemy automatically converts JSON columns to and from Python dictionaries, but sometimes you may need more control over this process. For those cases, custom serializer and deserializer can be implemented.

import json
from sqlalchemy.types import TypeDecorator, VARCHAR

class JSONEncodedDict(TypeDecorator):
    impl = VARCHAR

    def process_bind_param(self, value, dialect):
        if value is not None:
            value = json.dumps(value)
        return value

    def process_result_value(self, value, dialect):
        if value is not None:
            value = json.loads(value)
        return value

# Use it like...
class CustomJSONDataStore(Base):
    __tablename__ = 'custom_json_store'
    data = Column(JSONEncodedDict(255))

Storing data as JSON can influence your application’s performance. Indexes and proper design can mitigate overhead and improve read and write times.

Conclusion

SQLAlchemy provides a versatile and efficient way to store, query, and manipulate JSON data in a relational database. Whether you are using simple models for storing quick JSON data dumps, or building complex applications that perform advanced queries on JSON data, SQLAlchemy has you covered. Remember to adapt the size of your JSON columns to your needs and keep in mind database capabilities and potential performance impacts.