tiangolo / sqlmodel

SQL databases in Python, designed for simplicity, compatibility, and robustness.
https://sqlmodel.tiangolo.com/
MIT License
13.7k stars 616 forks source link

Add sessionmaker #75

Open hitman-gdg opened 2 years ago

hitman-gdg commented 2 years ago

First Check

Commit to Help

Example Code

Session = sessionmaker(engine)

Description

Add an sqlalchemy compatible sessionmaker that generates SqlModel sessions

Wanted Solution

I would like to have a working sessionmaker

Wanted Code

from sqlmodel import sessionmaker

Alternatives

No response

Operating System

macOS

Operating System Details

No response

SQLModel Version

0.0.4

Python Version

3.9.6

Additional Context

No response

Zaffer commented 2 years ago

Please add this because now it give error that .exec() does not exist on session if you using sqlalchemy import.

olzhasar commented 1 year ago

I faced the same issue and it looks like SQLAlchemy's sessionmaker works just fine with sqlmodel. The only caveat is that you have to provide sqlmodel.Session class to it:

from sqlmodel import Session
from sqlalchemy.orm import sessionmaker

TestSession = sessionmaker(class_=Session)
tiangolo commented 1 year ago

Why do you want a sessionmaker instead of using the new/future and more modern approach of using a with statement with a Session?

Just for completeness, AFAIK, the sessionmaker exists mainly because there was no with statement at the time.

gazpachoking commented 1 year ago

Why do you want a sessionmaker instead of using the new/future and more modern approach of using a with statement with a Session?

My understanding is that the point of the sessionmaker is so that you don't have to pass the configuration (e.g. the engine) to the Session every time. https://docs.sqlalchemy.org/en/14/orm/session_basics.html#using-a-sessionmaker

tobiasfeil commented 1 year ago

You can achieve the desired functionality like this:

from sqlmodel import Session as SQLModelSession
from contextlib import contextmanager

engine = ...

@contextmanager
def Session():
    session = SQLModelSession(engine)
    try:
        yield session
    finally:
        session.close()

Then, you can use Session as a context manager without passing the engine every time:

with Session() as session:
    ...
seanhuang514 commented 2 months ago

I faced a similar issue when I tried to call session.exec,then I got an error

AttributeError: 'Session' object has no attribute 'exec'

I found that if you use Sessionmaker like the below, you will get an instance of sqlalchemy.orm.session.Session instead of sqlmodel.orm.session.Session, and the instance of the SQLAlchemy session doesn't have the method exec, only the SQLModel session has.

from sqlalchemy.orm import sessionmaker
SessionLocal = sessionmaker(autoflush=False , bind=engine)

to fix the issue, just like @olzhasar mentioned, you have to pass Session that is imported from sqlmodel and pass to sessionmaker

from sqlmodel import Session as SQLModelSession
SessionLocal = sessionmaker(class_ = SQLModelSession, autoflush=False , bind=engine)

def get_session():
    with SessionLocal() as session:
        yield session

Session = Annotated[SQLModelSession, Depends(get_session)] 

# endpoint
@router.get("/db-test")
async def db_test(session: Session):
    statement = select(User)
    results = session.exec(statement)
    user = results.first()
    return user