I am trying to understand code, which does roughly the following:
# db.py module
engine = create_engine(DB_URL, pool_timeout=20, pool_recycle=1)
def get_session():
return scoped_session(sessionmaker(bind=engine, expire_on_commit=False))()
def get_base():
base = automap_base()
base.prepare(engine, reflect=True)
return base
base = get_base()
User = base.classes.user
in some function:
# other.py module
from db import get_base, get_session, User
def some_func():
sess = get_session()
# do something with sess and User:
user = sess.query(User).first()
User2 = get_base().classes.user
try:
check = sess.query(User2).first()
except:
sess.rollback()
# do more with sess
sess.commit()
The some_func
can be called in eg a celery task, but no greenlets or other similar monkey-patch concurrency tricks are in use.
I am wondering, what can be achieved by re-mapping metadata? Is my understanding correct, then due to scoped session SQLAlchemy will anyway have the same object? And in this case even session seems to be the same.
What can be the point?
My assumption about getting same object is wrong though:
(Pdb) pp user
<sqlalchemy.ext.automap.user object at 0x7f62e1a57390>
(Pdb) pp check
<sqlalchemy.ext.automap.user object at 0x7f62e0e93750>
(Pdb) pp user == check
False
(Pdb) pp user.id
1L
(Pdb) pp check.id
1L
(id
is a primary key, that is, unique)
So it seems that SQLAlchemy keeps objects from different base separately.
My best guess so far is that this trick allows to have, for example, user existence test outside of currently running transaction.
Most of the time it is not necessary and just slows the application down. The database schema does not usually change too often while the application is running, and simple changes should not matter (see "Data independence"). Redoing reflection etc. is just something people seem to do – maybe due to fear of using globals. On the other hand in your example it first seems that in db.py
reflection is done only once to produce the global base
and User
classes.
The same applies to scoped session registries. The registry itself is meant to serve thread-local sessions, so there is no point in recreating it all the time. Instead it should be an application wide singleton. It should be noted that using scoped sessions means that your application uses threads in a manner compatible with it, or in other words a single thread should be handling a single job, such as a request/response etc., so that the lifetime of a session binds naturally to the lifetime of a thread.
Your assumption about getting the same object breaks due to the recreation of base and model classes. Though they represent the same row in the database, they are different models and as such produce different objects in the session.