scoped_session无query()方法却可调用?其实现原理是什么
Great question! Let's break down exactly what's happening here—it's a common point of confusion with how SQLAlchemy manages sessions, so it's smart to dig into the underlying mechanism.
1. scoped_session is a Proxy, Not a Direct Session Instance
First off, a scoped_session object isn't a real Session instance itself—it's a proxy/wrapper that manages a single Session per scope (usually per thread by default).
The scoped_session class doesn't define a query() method, but it does implement Python's __getattr__ magic method. This method triggers whenever you try to access an attribute or method that scoped_session doesn't have natively. When this happens, scoped_session forwards the request directly to the actual Session instance it's managing for your current scope.
2. The Real query() Method Lives in the Session Class
SQLAlchemy's core Session class does have a built-in query() method. This method creates a Query object tied to that session, which you can then filter, sort, or manipulate further.
When you run your code:
session = scoped_session(sessionmaker()) q = session.query(table_name).filter(table_name.id==1)
Here's the step-by-step flow:
- You call
query()on yourscoped_sessioninstance. - Since
scoped_sessionhas noquery()method,__getattr__kicks in. scoped_sessionretrieves the activeSessioninstance for your current scope (via its internal registry system).- It calls the
query()method on that realSessioninstance, passing yourtable_nameas an argument. - The result is a valid
Queryobject, just like if you were using a directSessioninstance.
3. What's query_property() For, Then?
You noticed scoped_session includes query_property()—this is a separate but related feature.
query_property() is used to attach a query attribute directly to your model classes for convenience. For example:
from sqlalchemy.orm import scoped_session, sessionmaker, query_property session = scoped_session(sessionmaker()) class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) # Attach a query property to the model query = query_property(session)
Now you can run queries like User.query.filter(User.id == 1) without explicitly calling session.query(User). Under the hood, this property uses the scoped_session to fetch the active Session and then calls its query() method—it's just a shortcut for model-level queries.
To Sum It Up
scoped_sessionacts as a proxy, forwarding unknown method/attribute calls to the realSessionin the current scope (via__getattr__).- The
query()method you're using belongs to the underlyingSessioninstance, notscoped_sessionitself. query_property()is a separate tool for adding model-bound query access, but it relies on the same underlyingSession.query()mechanism.
内容的提问来源于stack exchange,提问作者cuihaikuo

