summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/__init__.py37
-rw-r--r--lib/sqlalchemy/orm/dynamic.py3
-rw-r--r--lib/sqlalchemy/orm/session.py76
-rw-r--r--lib/sqlalchemy/orm/shard.py2
4 files changed, 109 insertions, 9 deletions
diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py
index 2c1a4ffc4..871580660 100644
--- a/lib/sqlalchemy/orm/__init__.py
+++ b/lib/sqlalchemy/orm/__init__.py
@@ -21,24 +21,55 @@ from sqlalchemy.orm.query import Query
from sqlalchemy.orm.util import polymorphic_union
from sqlalchemy.orm.session import Session as _Session
from sqlalchemy.orm.session import object_session, attribute_manager, sessionmaker
-from sqlalchemy.orm.scoping import ScopedSession as scoped_session
+from sqlalchemy.orm.scoping import ScopedSession
__all__ = [ 'relation', 'column_property', 'composite', 'backref', 'eagerload',
'eagerload_all', 'lazyload', 'noload', 'deferred', 'defer',
'undefer', 'undefer_group', 'extension', 'mapper', 'clear_mappers',
'compile_mappers', 'class_mapper', 'object_mapper', 'sessionmaker',
- 'scoped_session', 'dynamic_loader', 'MapperExtension', 'Query', 'polymorphic_union',
+ 'scoped_session', 'dynamic_loader', 'MapperExtension', 'polymorphic_union',
'create_session', 'synonym', 'contains_alias',
'contains_eager', 'EXT_CONTINUE', 'EXT_STOP', 'EXT_PASS',
'object_session', 'PropComparator' ]
+def scoped_session(session_factory, scopefunc=None):
+ """Provides thread-local management of Sessions.
+
+ Usage::
+
+ Session = scoped_session(sessionmaker(autoflush=True))
+
+ To instantiate a Session object which is part of the scoped
+ context, instantiate normally::
+
+ session = Session()
+
+ Most session methods are available as classmethods from
+ the scoped session::
+
+ Session.commit()
+ Session.close()
+
+ To map classes so that new instances are saved in the current
+ Session automatically, as well as to provide session-aware
+ class attributes such as "query", use the `mapper` classmethod
+ from the scoped session::
+
+ mapper = Session.mapper
+ mapper(Class, table, ...)
+
+ """
+
+ return ScopedSession(session_factory, scopefunc=scopefunc)
+
def create_session(bind=None, **kwargs):
"""create a new [sqlalchemy.orm.session#Session].
The session by default does not begin a transaction, and requires that
flush() be called explicitly in order to persist results to the database.
- It is recommended to use the sessionmaker() function instead of create_session().
+ It is recommended to use the [sqlalchemy.orm#sessionmaker()] function
+ instead of create_session().
"""
kwargs.setdefault('autoflush', False)
kwargs.setdefault('transactional', False)
diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py
index d06b874c9..dee2e28ce 100644
--- a/lib/sqlalchemy/orm/dynamic.py
+++ b/lib/sqlalchemy/orm/dynamic.py
@@ -2,7 +2,8 @@
a special AttributeHistory on the 'write' side."""
from sqlalchemy import exceptions
-from sqlalchemy.orm import attributes, Query, object_session
+from sqlalchemy.orm import attributes, object_session
+from sqlalchemy.orm.query import Query
from sqlalchemy.orm.mapper import has_identity
class DynamicCollectionAttribute(attributes.InstrumentedAttribute):
diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py
index 80c1a5b0d..1b0c1a9a2 100644
--- a/lib/sqlalchemy/orm/session.py
+++ b/lib/sqlalchemy/orm/session.py
@@ -159,11 +159,79 @@ class SessionTransaction(object):
self.rollback()
class Session(object):
- """Encapsulates a set of objects being operated upon within an
- object-relational operation.
+ """Encapsulates a set of objects being operated upon within an object-relational operation.
- The Session object is **not** threadsafe. For thread-management
- of Sessions, see the ``sqlalchemy.ext.sessioncontext`` module.
+ The Session is the front end to SQLAlchemy's **Unit of Work** implementation. The concept
+ behind Unit of Work is to track modifications to a field of objects, and then be able to
+ flush those changes to the database in a single operation.
+
+ SQLAlchemy's unit of work includes these functions:
+
+ * The ability to track in-memory changes on scalar- and collection-based object
+ attributes, such that database persistence operations can be assembled based on those
+ changes.
+
+ * The ability to organize individual SQL queries and population of newly generated
+ primary and foreign key-holding attributes during a persist operation
+ such that referential integrity is maintained at all times.
+
+ * The ability to maintain insert ordering against the order in which
+ new instances were added to the session.
+
+ * an Identity Map, which is a dictionary keying instances to their unique primary key
+ identity. This ensures that only one copy of a particular entity is ever present
+ within the session, even if repeated load operations for the same entity occur. This
+ allows many parts of an application to get a handle to a particular object without
+ any chance of modifications going to two different places.
+
+ When dealing with instances of mapped classes, an instance may be *attached* to a
+ particular Session, else it is *unattached* . An instance also may or may not correspond
+ to an actual row in the database. These conditions break up into four distinct states:
+
+ * *Transient* - a transient instance exists within memory only and is not associated with
+ any Session. It also has no database identity and does not have a corresponding record
+ in the database. When a new instance of a class is constructed, and no default session
+ context exists with which to automatically attach the new instance, it is a transient
+ instance. The instance can then be saved to a particular session in which case it
+ becomes a *pending* instance. If a default session context exists, new instances are
+ added to that Session by default and therefore become *pending* instances immediately.
+
+ * *Pending* - a pending instance is a Session-attached object that has not yet been
+ assigned a database identity. When the Session is flushed (i.e. changes are persisted to
+ the database), a pending instance becomes persistent.
+
+ * *Persistent* - a persistent instance has a database identity and a corresponding record
+ in the database, and is also associated with a particular Session. By "database
+ identity" we mean the object is associated with a table or relational concept in the
+ database combined with a particular primary key in that table. Objects that are loaded
+ by SQLAlchemy in the context of a particular session are automatically considered
+ persistent, as are formerly pending instances which have been subject to a session
+ `flush()`.
+
+ * *Detached* - a detached instance is an instance which has a database identity and
+ corresponding row in the database, but is not attached to any Session. This occurs when
+ an instance has been removed from a Session, either because the session itself was
+ cleared or closed, or the instance was explicitly removed from the Session. The object
+ can be re-attached to a session in which case it becomes Persistent again; any
+ un-persisted changes that exist on the instance, whether they occurred during its
+ previous persistent state or during its detached state will be detected and maintained
+ by the new session. Detached instances are useful when an application needs to represent
+ a long-running operation across multiple Sessions, needs to store an object in a
+ serialized state and then restore it later (such as within an HTTP "session" object), or
+ in some cases where code needs to load instances locally which will later be associated
+ with some other Session.
+
+ The session methods which control instance state include ``save()``, ``update()``,
+ ``save_or_update()``, ``delete()``, ``merge()``, and ``expunge()``.
+
+ The Session object is **not** threadsafe, particularly during flush operations. A session
+ which is only read from (i.e. is never flushed) can be used by concurrent threads if it's
+ acceptable that some object instances may be loaded twice.
+
+ The typical pattern to managing Sessions in a multi-threaded environment is either to use
+ mutexes to limit concurrent access to one thread at a time, or more commonly to establish
+ a unique session for every thread, using a threadlocal variable. SQLAlchemy provides
+ a thread-managed Session adapter, provided by the [sqlalchemy.orm#scoped_session()] function.
"""
def __init__(self, bind=None, autoflush=True, transactional=False, twophase=False, echo_uow=False, weak_identity_map=False):
diff --git a/lib/sqlalchemy/orm/shard.py b/lib/sqlalchemy/orm/shard.py
index 9d4396d2b..69d692167 100644
--- a/lib/sqlalchemy/orm/shard.py
+++ b/lib/sqlalchemy/orm/shard.py
@@ -1,5 +1,5 @@
from sqlalchemy.orm.session import Session
-from sqlalchemy.orm import Query
+from sqlalchemy.orm.query import Query
__all__ = ['ShardedSession', 'ShardedQuery']