The Session: add, commit and get

SQLAlchemy · Essentials · 10 min

The Session is the ORM's single entry point for persisting and loading objects.

A Session is the ORM's workspace. It holds a connection and a transaction, tracks the objects you load or add, and writes their changes to the database.

The basic cycle:

  • session.add(obj) or session.add_all([...]) marks new objects as pending.
  • session.commit() flushes pending changes as INSERT/UPDATE/DELETE statements, then commits the transaction.
  • session.get(User, 5) loads by primary key, returning None if there's no such row (and returning the already-loaded object without a query if it's in the session).

Use the Session as a context manager so it's closed at the end of the block. In an application you create a factory once with SessionLocal = sessionmaker(engine) and open short-lived sessions from it, typically one per web request or job.

After commit(), by default all objects are expired: their attributes are reloaded from the database the next time you access them. That guarantees fresh data after the transaction but surprises people who access objects after closing the session. Set expire_on_commit=False on the sessionmaker when you need to return objects from a function after committing.

If something fails, session.rollback() discards the transaction; leaving the with block without committing also rolls back.

Example

from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, sessionmaker

class Base(DeclarativeBase):
    pass

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

engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
SessionLocal = sessionmaker(engine)

with SessionLocal() as session:
    ada = User(name="ada")
    session.add_all([ada, User(name="linus")])
    session.commit()
    print(ada.id)              # 1: assigned during the flush

with SessionLocal() as session:
    print(session.get(User, 2).name)  # linus
    print(session.get(User, 99))      # None

Remember

  • add() stages objects; commit() flushes and commits
  • session.get(Model, pk) loads by primary key or returns None
  • Create a sessionmaker once, open short-lived sessions from it
  • Objects are expired after commit unless expire_on_commit=False

Watch out for

  • Keeping one global Session for the whole application instead of one per unit of work.

Check yourself

  1. What does session.get(User, 42) return when no row has id 42?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.sqlalchemy.org/en/20/orm/session_basics.html