SQLAlchemy

raw JSON →
2.0.48 verified Tue May 12 auth: no python install: verified quickstart: verified

The most widely used Python SQL toolkit and ORM. v2.0 released January 2023 — massive breaking change from v1.x. The entire ORM query API shifted from session.query() to select(). engine.execute() removed. Passing raw strings to execute() removed. Typed mapped_column() replaces Column(). Current version: 2.0.48 (Mar 2026). Flask-SQLAlchemy's Model.query pattern is also legacy in v2.

pip install sqlalchemy
error AttributeError: 'Session' object has no attribute 'query'
cause In SQLAlchemy 2.0, the `session.query()` method has been removed; ORM queries now use the `select()` construct.
fix
Replace session.query(MyModel).filter(...).all() with session.execute(select(MyModel).filter(...)).scalars().all().
error ArgumentError: Textual SQL not allowed directly on Connection.execute(). Please use text() or bind parameters.
cause SQLAlchemy 2.0 requires explicit `text()` constructs for executing raw SQL strings with `connection.execute()` or `session.execute()`.
fix
Wrap raw SQL strings in sqlalchemy.text(): connection.execute(text('SELECT * FROM my_table')).
error TypeError: Mapped expects a type annotation argument
cause When defining declarative models in SQLAlchemy 2.0 using `Mapped`, column definitions should typically use `mapped_column()` or just type annotations, not the `Column()` construct without an explicit type hint.
fix
Use mapped_column() instead of Column() for mapped attributes: id: Mapped[int] = mapped_column(primary_key=True).
error AttributeError: type object 'User' has no attribute 'query'
cause In Flask-SQLAlchemy when using SQLAlchemy 2.0, the `Model.query` attribute is deprecated in favor of direct SQLAlchemy 2.0-style `session.execute(select(...))` queries.
fix
Use db.session.execute(db.select(User).filter_by(username='test')) instead of User.query.filter_by(username='test').first().
breaking engine.execute() removed in v2.0. Raises AttributeError. Most LLM-generated SQLAlchemy code uses engine.execute().
fix Use 'with engine.connect() as conn: conn.execute(text(...))'
breaking Passing raw strings to execute() removed. conn.execute('SELECT 1') raises ArgumentError in v2.
fix from sqlalchemy import text; conn.execute(text('SELECT 1'))
breaking declarative_base() from sqlalchemy.ext.declarative is legacy in v2. Still works but generates RemovedIn20Warning.
fix from sqlalchemy.orm import DeclarativeBase; class Base(DeclarativeBase): pass
gotcha session.query() is legacy in v2 — still works but not recommended. Flask-SQLAlchemy's Model.query is also legacy. LLMs trained pre-2023 generate session.query() patterns.
fix Replace session.query(Model).filter(...) with session.scalars(select(Model).where(...))
gotcha session.execute() now returns a Result object. For ORM models use session.scalars() to get model instances directly, not session.execute().
fix users = session.scalars(select(User)).all() — not session.execute(select(User)).all()
gotcha Autocommit behavior changed in v2. Connections no longer autocommit. Must explicitly use with engine.begin() for autocommit or session.commit().
fix Use 'with engine.begin() as conn:' for autocommit. Or call session.commit() explicitly.
gotcha Column() without type annotations still works but loses IDE/mypy type inference. mapped_column() with Mapped[] is the v2 typed approach.
fix id: Mapped[int] = mapped_column(primary_key=True)
pip install 'sqlalchemy[asyncio]'
python os / libc variant status wheel install import disk
3.10 alpine (musl) asyncio - - 0.54s 42.4M
3.10 alpine (musl) sqlalchemy - - 0.52s 42.4M
3.10 slim (glibc) asyncio - - 0.36s 41M
3.10 slim (glibc) sqlalchemy - - 0.36s 41M
3.11 alpine (musl) asyncio - - 0.79s 47.5M
3.11 alpine (musl) sqlalchemy - - 0.79s 47.5M
3.11 slim (glibc) asyncio - - 0.66s 46M
3.11 slim (glibc) sqlalchemy - - 0.65s 46M
3.12 alpine (musl) asyncio - - 0.86s 38.8M
3.12 alpine (musl) sqlalchemy - - 0.84s 38.8M
3.12 slim (glibc) asyncio - - 0.85s 37M
3.12 slim (glibc) sqlalchemy - - 0.83s 37M
3.13 alpine (musl) asyncio - - 0.81s 38.2M
3.13 alpine (musl) sqlalchemy - - 0.81s 38.2M
3.13 slim (glibc) asyncio - - 0.79s 37M
3.13 slim (glibc) sqlalchemy - - 0.80s 37M
3.9 alpine (musl) asyncio - - 0.45s 41.1M
3.9 alpine (musl) sqlalchemy - - 0.46s 41.1M
3.9 slim (glibc) asyncio - - 0.44s 40M
3.9 slim (glibc) sqlalchemy - - 0.43s 40M

SQLAlchemy 2.0 ORM quickstart with typed models.

# pip install sqlalchemy
from sqlalchemy import create_engine, String, select, text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = 'users'
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(50))

engine = create_engine('sqlite:///test.db')
Base.metadata.create_all(engine)

with Session(engine) as session:
    # Insert
    session.add(User(name='Alice'))
    session.commit()

    # Query — v2 style
    stmt = select(User).where(User.name == 'Alice')
    user = session.scalars(stmt).first()
    print(user.name)  # 'Alice'