:class:`.Session` is a regular Python class which can
be directly instantiated. However, to standardize how sessions are configured
-and acquired, the :
func:`.sessionmaker` function is normally
+and acquired, the ::`.sessionmaker` is normally
used to create a top level :class:`.Session`
configuration which can then be used throughout an application without the
need to repeat the configurational arguments.
-The usage of :
func:`.sessionmaker` is illustrated below:
+The usage of ::`.sessionmaker` is illustrated below:
.. sourcecode:: python+sql
-Above, the :func:`.sessionmaker` call creates a class for us,
-which we assign to the name ``Session``. This class is a subclass of the
-actual :class:`.Session` class, which when instantiated, will
-use the arguments we've given the function, in this case
-to use a particular :class:`.Engine` for connection resources.
+Above, the :class:`.sessionmaker` call creates a factory for us,
+which we assign to the name ``Session``. This factory, when
+called, will create a new :class:`.Session` object using the configurational
+arguments we've given the factory. In this case, as is typical,
+we've configured the factory to specify a particular :class:`.Engine` for
-A typical setup will associate the :
func:`.sessionmaker` with an :class:`.Engine`,
+A typical setup will associate the ::`.sessionmaker` with an :class:`.Engine`,
so that each :class:`.Session` generated will use this :class:`.Engine`
to acquire connection resources. This association can
be set up as in the example above, using the ``bind`` argument.
-When you write your application, place the result of the
-:func:`.sessionmaker` call at the global level. The resulting
-``Session`` class, configured for your application, should then
+When you write your application, place the
+:class:`.sessionmaker` factory at the global level. This
be used by the rest of the applcation as the source of new :class:`.Session`
+instances, keeping the configuration for how :class:`.Session` objects
+are constructed in one place.
-An extremely common step taken by applications, including virtually
-all web applications, is to further wrap the :func:`.sessionmaker`
-construct in a so-called "contextual" session, provided by the
-:func:`.scoped_session` construct. This construct places the :func:`.sessionmaker`
-into a **registry** that maintains a single :class:`.Session` per
-application thread. Information on using contextual sessions
-is at :ref:`unitofwork_contextual`.
+The :class:`.sessionmaker` factory can also be used in conjunction with
+other helpers, which are passed a user-defined :class:`.sessionmaker` that
+is then maintained by the helper. Some of these helpers are discussed in the
Adding Additional Configuration to an Existing sessionmaker()
-A common scenario is where the :
func:`.sessionmaker` is invoked
+A common scenario is where the ::`.sessionmaker` is invoked
at module import time, however the generation of one or more :class:`.Engine`
-instances to be associated with the :func:`.sessionmaker` has not yet proceeded.
-For this use case, the :func:`.sessionmaker` construct offers the
+instances to be associated with the :class:`.sessionmaker` has not yet proceeded.
+For this use case, the :class:`.sessionmaker` construct offers the
:meth:`.sessionmaker.configure` method, which will place additional configuration
-directives into an existing :
func:`.sessionmaker` that will take place
+directives into an existing ::`.sessionmaker` that will take place
when the construct is invoked::
source of connectivity, or a :class:`.Session` that should
have other arguments such as ``expire_on_commit`` established differently from
what most of the application wants, specific arguments can be passed to the
-:func:`.sessionmaker` construct's class itself. These arguments will override whatever
+:class:`.sessionmaker` factory's :meth:`.sessionmaker.__call__` method.
+These arguments will override whatever
configurations have already been placed, such as below, where a new :class:`.Session`
is constructed against a specific :class:`.Connection`::
It's helpful to know the states which an instance can have within a session:
-* *Transient* - an instance that's not in a session, and is not saved to the
+* *Transient* - an instance that's not in a session, and is not saved to the
database; i.e. it has no database identity. The only relationship such an
object has to the ORM is that its class has a ``mapper()`` associated with
-* *Pending* - when you :func:`~sqlalchemy.orm.session.Session.add` a transient
+* *Pending* - when you :func:`~sqlalchemy.orm.session.Session.add` a transient
instance, it becomes pending. It still wasn't actually flushed to the
database yet, but it will be when the next flush occurs.
-* *Persistent* - An instance which is present in the session and has a record
+* *Persistent* - An instance which is present in the session and has a record
in the database. You get persistent instances by either flushing so that the
pending instances become persistent, or by querying the database for
existing instances (or moving persistent instances from other sessions into
-* *Detached* - an instance which has a record in the database, but is not in
+* *Detached* - an instance which has a record in the database, but is not in
any session. There's nothing wrong with this, and you can use objects
normally when they're detached, **except** they will not be able to issue
any SQL in order to load collections or attributes which are not yet loaded,
or were marked as "expired".
Knowing these states is important, since the
~sqlalchemy.orm.session.Session` tries to be strict about ambiguous
+:class:`.Session` tries to be strict about ambiguous
operations (such as trying to save the same object to two different sessions
Session Frequently Asked Questions
-* When do I make a :
+* When do I make a ::`.sessionmaker` ?
Just one time, somewhere in your application's global scope. It should be
looked upon as part of your application's configuration. If your
application has three .py files in a package, you could, for example,
- place the :
func:`.sessionmaker` line in your ``__init__.py`` file; from
+ place the ::`.sessionmaker` line in your ``__init__.py`` file; from
that point on your other modules say "from mypackage import Session". That
way, everyone else just uses :class:`.Session()`,
and the configuration of that session is controlled by that central point.
If your application starts up, does imports, but does not know what
database it's going to be connecting to, you can bind the
:class:`.Session` at the "class" level to the
- engine later on, using
+ engine later on, using configure`.
In the examples in this section, we will frequently show the
- :func:`.sessionmaker` being created right above the line where we actually
- invoke :class:`~sqlalchemy.orm.session.Session()`. But that's just for
- example's sake ! In reality, the :func:`.sessionmaker` would be somewhere
- at the module level, and your individual
- :class:`~sqlalchemy.orm.session.Session()` calls would be sprinkled all
- throughout your app, such as in a web application within each controller
+ :class:`.sessionmaker` being created right above the line where we actually
+ invoke :class:`.Session`. But that's just for
+ example's sake! In reality, the :class:`.sessionmaker` would be somewhere
+ at the module level. The calls to instantiate :class:`.Session`
+ would then be placed at the point in the application where database
+ conversations begin (see :ref:`session_faq_whentocreate`).
-* When do I
make a :class:`.Session` ?
+* When do I a :class:`.Session` ?
- You typically invoke :class:`.Session` when you first need to talk to your
- database, and want to save some objects or load some existing ones. It
- then remains in use for the lifespan of a particular database
- conversation, which includes not just the initial loading of objects but
- throughout the whole usage of those instances.
+ A :class:`.Session` is typically constructed at the beginning of a logical
+ operation where database access is potentially anticipated.
- Objects become detached if their owning session is discarded. They are
- still functional in the detached state if the user has ensured that their
- state has not been expired before detachment, but they will not be able to
- represent the current state of database data. Because of this, it's best
- to consider persisted objects as an extension of the state of a particular
- :class:`.Session`, and to keep that session around until all referenced
- objects have been discarded.
+ The :class:`.Session`, whenever it is used to talk to the database,
+ begins a database transaction as soon as it starts communicating.
+ Assuming the ``autocommit`` flag is left at its recommended default
+ of ``False``, this transaction remains in progress until the :class:`.Session`
+ is rolled back, committed, or closed. The :class:`.Session` will
+ begin a new transaction if it is used again, subsequent to the previous
+ transaction ending; from this it follows that the :class:`.Session`
+ is capable of having a lifespan across many transactions, though only
+ one at a time. We refer to these two concepts as *transaction scope*
- An exception to this is when objects are placed in caches or otherwise
- shared among threads or processes, in which case their detached state can
- be stored, transmitted, or shared. However, the state of detached objects
- should still be transferred back into a new :class:`.Session` using
- :meth:`.Session.add` or :meth:`.Session.merge` before working with the
- object (or in the case of merge, its state) again.
+ The implication here is that the SQLAlchemy ORM is encouraging the
+ developer to establish these two scopes in his or her application,
+ including not only when the scopes begin and end, but also the
+ expanse of those scopes, for example should a single
+ :class:`.Session` instance be local to the execution flow within a
+ function or method, should it be a global object used by the
+ entire application, or somewhere in between these two.
- It is also very common that a :class:`.Session` as well as its associated
- objects are only referenced by a single thread. Sharing objects between
- threads is most safely accomplished by sharing their state among multiple
- instances of those objects, each associated with a distinct
- :class:`.Session` per thread, :meth:`.Session.merge` to transfer state
- between threads. This pattern is not a strict requirement by any means,
- but it has the least chance of introducing concurrency issues.
+ The burden placed on the developer to determine this scope is one
+ area where the SQLAlchemy ORM necessarily has a strong opinion
+ about how the database should be used. The unit-of-work pattern
+ is specifically one of accumulating changes over time and flushing
+ them periodically, keeping in-memory state in sync with what's
+ known to be present in a local transaction. This pattern is only
+ effective when meaningful transaction scopes are in place.
- To help with the recommended :class:`.Session` -per-thread,
- :class:`.Session` -per-set-of-objects patterns, the
- :func:`.scoped_session` function is provided which produces a
- thread-managed registry of :class:`.Session` objects. It is commonly used
- in web applications so that a single global variable can be used to safely
- represent transactional sessions with sets of objects, localized to a
- single thread. More on this object is in :ref:`unitofwork_contextual`.
+ It's usually not very hard to determine the best points at which
+ to begin and end the scope of a :class:`.Session`, though the wide
+ variety of application architectures possible can introduce
+ challenging situations.
+ A common choice is to tear down the :class:`.Session` at the same
+ time the transaction ends, meaning the transaction and session scopes
+ are the same. This is a great choice to start out with as it
+ removes the need to consider session scope as separate from transaction
+ While there's no one-size-fits-all recommendation for how transaction
+ scope should be determined, there are common patterns. Especially
+ if one is writing a web application, the choice is pretty much established.
+ A web application is the easiest case because such an appication is already
+ constructed around a single, consistent scope - this is the **request**,
+ which represents an incoming request from a browser, the processing
+ of that request to formulate a response, and finally the delivery of that
+ response back to the client. Integrating web applications with the
+ :class:`.Session` is then the straightforward task of linking the
+ scope of the :class:`.Session` to that of the request. The :class:`.Session`
+ can be established as the request begins, or using a **lazy initialization**
+ pattern which establishes one as soon as it is needed. The request
+ then proceeds, with some system in place where application logic can access
+ the current :class:`.Session` in a manner associated with how the actual
+ requset object is accessed. As the request ends, the :class:`.Session`
+ is torn down as well, usually through the usage of event hooks provided
+ by the web framework. The transaction used by the :class:`.Session`
+ may also be committed at this point, or alternatively the application may
+ opt for an explicit commit pattern, only committing for those requests
+ where one is warranted, but still always tearing down the :class:`.Session`
+ unconditionally at the end.
+ Most web frameworks include infrastructure to establish a single
+ :class:`.Session`, associated with the request, which is correctly
+ constructed and torn down corresponding
+ torn down at the end of a request. Such infrastructure pieces
+ include products such as `Flask-SQLAlchemy <http://packages.python.org/Flask-SQLAlchemy/>`_,
+ for usage in conjunction with the Flask web framework,
+ and `Zope-SQLAlchemy <http://pypi.python.org/pypi/zope.sqlalchemy>`_,
+ for usage in conjunction with the Pyramid and Zope frameworks.
+ SQLAlchemy strongly recommends that these products be used as
+ In those situations where integration libraries are not available,
+ SQLAlchemy includes its own "helper" class known as
+ :class:`.scoped_session`. This object actually is used as the basis
+ of some integration packages, and provides both a quick way
+ to associate a :class:`.Session` with the current thread, as well as
+ patterns to associate :class:`.Session` objects with other kinds of
+ As mentioned before, for non-web applications there is no one clear
+ pattern, as applications themselves don't have just one pattern
+ of architecture. The best strategy is to attempt to demarcate
+ "operations", points at which a particular thread begins to perform
+ a series of operations for some period of time, which can be committed
+ at the end. Some examples:
+ * A background daemon which spawns off child forks for example
+ would want to create a :class:`.Session` local to each child
+ process work with that :class:`.Session` through the life of the "job"
+ that the fork is handling, then tear it down when the job is completed.
+ * For a command-line script, the application would create a single, global
+ :class:`.Session` that is established when the program begins to do its
+ work, and commits it right as the program is completing its task.
+ * For a GUI interface-driven application, the scope of the :class:`.Session`
+ may best be within the scope of a user-generated event, such as a button
+ push. Or, the scope may correspond to explicit user interaction, such as
+ the user "opening" a series of records, then "saving" them.
* Is the Session a cache ?
session = Session.object_session(someobject)
- single: thread safety; sessions
- single: thread safety; Session
+* Is the session thread-safe?
-* Is the session thread-safe?
+ The :class:`.Session` is very much intended to be used in a
+ **non-concurrent** fashion, which usually means in only one thread at a
Nope. It has no thread synchronization of any kind built in, and
particularly when you do a flush operation, it definitely is not open to
A multithreaded application is usually going to want to make usage of
func:`.scoped_session` to transparently manage sessions per thread.
+ ::`.scoped_session` to transparently manage sessions per thread.
More on this at :ref:`unitofwork_contextual`.
The "flush-on-Query" aspect of the behavior can be disabled by constructing
:func:`.sessionmaker` with the flag ``autoflush=False``::
+:`.sessionmaker` with the flag ``autoflush=False``::
Session = sessionmaker(autoflush=False)
attribute access or by them being present in a
:class:`~sqlalchemy.orm.query.Query` result set, they receive the most recent
state. To disable this behavior, configure
:func:`.sessionmaker` with ``expire_on_commit=False``.
+:`.sessionmaker` with ``expire_on_commit=False``.
Normally, instances loaded into the :class:`~sqlalchemy.orm.session.Session`
are never changed by subsequent queries; the assumption is that the current
full flush, these collections are all empty, and all objects are again weakly
referenced. To disable the weak referencing behavior and force all objects
within the session to remain until explicitly expunged, configure
:func:`.sessionmaker` with the ``weak_identity_map=False``
+:`.sessionmaker` with the ``weak_identity_map=False``
-A common need in applications, particularly those built around web frameworks,
-is the ability to "share" a :class:`~sqlalchemy.orm.session.Session` object
-among disparate parts of an application, without needing to pass the object
-explicitly to all method and function calls. What you're really looking for is
-some kind of "global" session object, or at least "global" to all the parts of
-an application which are tasked with servicing the current request. For this
-pattern, SQLAlchemy provides the ability to enhance the
-:class:`~sqlalchemy.orm.session.Session` class generated by
-:func:`.sessionmaker` to provide auto-contextualizing support.
-This means that whenever you create a :class:`~sqlalchemy.orm.session.Session`
-instance with its constructor, you get an *existing*
-:class:`~sqlalchemy.orm.session.Session` object which is bound to some
-"context". By default, this context is the current thread. This feature is
-what previously was accomplished using the ``sessioncontext`` SQLAlchemy
+Recall from the section :ref:`session_faq_whentocreate`, the concept of
+"session scopes" was introduced, with an emphasis on web applications
+and the practice of linking the scope of a :class:`.Session` with that
+of a web request. Most modern web frameworks include integration tools
+so that the scope of the :class:`.Session` can be managed automatically,
+and these tools should be used as they are available.
-Creating a Thread-local Context
+SQLAlchemy includes its own helper object, which helps with the establishment
+of user-defined :class:`.Session` scopes. It is also used by third-party
+integration systems to help construct their integration schemes.
-The :func:`~sqlalchemy.orm.scoped_session` function wraps around the
-:func:`.sessionmaker` function, and produces an object which
-behaves the same as the :class:`~sqlalchemy.orm.session.Session` subclass
-returned by :func:`.sessionmaker`::
+The object is the :class:`.scoped_session` object, and it represents a
+**registry** of :class:`.Session` objects. If you're not familiar with the
+registry pattern, a good introduction can be found in `Patterns of Enterprise
- from sqlalchemy.orm import scoped_session, sessionmaker
- Session = scoped_session(sessionmaker())
-However, when you instantiate this :class:`~sqlalchemy.orm.session.Session`
-"class", in reality the object is pulled from a threadlocal variable, or if it
-doesn't exist yet, it's created using the underlying class generated by
+ The :class:`.scoped_session` object is a very popular and useful object
+ used by many SQLAlchemy applications. However, it is important to note
+ that it presents **only one approach** to the issue of :class:`.Session`
+ management. If you're new to SQLAlchemy, and especially if the
+ term "thread-local variable" seems strange to you, we recommend that
+ if possible you familiarize first with an off-the-shelf integration
+ system such as `Flask-SQLAlchemy <http://packages.python.org/Flask-SQLAlchemy/>`_
+ or `zope.sqlalchemy <http://pypi.python.org/pypi/zope.sqlalchemy>`_.
- >>> # call Session() the first time. the new Session instance is created.
- >>> session = Session()
+A :class:`.scoped_session` is constructed by calling it, passing it a
+**factory** which can create new :class:`.Session` objects. A factory
+is just something that produces a new object when called, and in the
+case of :class:`.Session`, the most common factory is the :class:`.sessionmaker`,
+introduced earlier in this section. Below we illustrate this usage::
- >>> # later, in the same application thread, someone else calls Session()
- >>> session2 = Session()
+ >>> from sqlalchemy.orm import scoped_session
+ >>> from sqlalchemy.orm import sessionmaker
- >>> # the two Session objects are *the same* object
- >>> session is session2
+ >>> session_factory = sessionmaker(bind=some_engine)
+ >>> Session = scoped_session(session_factory)
+The :class:`.scoped_session` object we've created will now call upon the
+:class:`.sessionmaker` when we "call" the registry::
+ >>> some_session = Session()
+Above, ``some_session`` is an instance of :class:`.Session`, which we
+can now use to talk to the database. This same :class:`.Session` is also
+present within the :class:`.scoped_session` registry we've created. If
+we call upon the registry a second time, we get back the **same** :class:`.Session`::
+ >>> some_other_session = Session()
+ >>> some_session is some_other_session
-Since the :class:`~sqlalchemy.orm.session.Session()` constructor now returns
-the same :class:`~sqlalchemy.orm.session.Session` object every time within the
-current thread, the object returned by :func:`~sqlalchemy.orm.scoped_session`
-also implements most of the :class:`~sqlalchemy.orm.session.Session` methods
-and properties at the "class" level, such that you don't even need to
+This pattern allows disparate sections of the application to call upon a global
+:class:`.scoped_session`, so that all those areas may share the same session
+without the need to pass it explicitly. The :class:`.Session` we've established
+in our registry will remain, until we explicitly tell our regsitry to dispose of it,
+by calling :meth:`.scoped_session.remove`::
- # save to the contextual session, without instantiating
+The :meth:`.scoped_session.remove` method first calls :meth:`.Session.close` on
+the current :class:`.Session`, which has the effect of releasing any connection/transactional
+resources owned by the :class:`.Session` first, then discarding the :class:`.Session`
+itself. "Releasing" here means that any pending transaction will be rolled back
- # view the "new" attribute
- assert u1 in Session.new
+At this point, the :class:`.scoped_session` object is "empty", and will create
+a **new** :class:`.Session` when called again. As illustrated below, this
+is not the same :class:`.Session` we had before::
+ >>> new_session = Session()
+ >>> new_session is some_session
-The contextual session may be disposed of by calling ``Session.remove()``::
+The above series of steps illustrates the idea of the "registry" pattern in a
+nutshell. With that basic idea in hand, we can discuss some of the details
+of how this pattern proceeds.
- # remove current contextual session
-After ``remove()`` is called, the next operation with the contextual session
-will start a new :class:`~sqlalchemy.orm.session.Session` for the current
+The job of the :class:`.scoped_session` is simple; hold onto a :class:`.Session`
+for all who ask for it. As a means of producing more transparent access to this
+:class:`.Session`, the :class:`.scoped_session` also includes **proxy behavior**,
+meaning that the registry itself can be treated just like a :class:`.Session`
+directly; when methods are called on this object, they are **proxied** to the
+underlying :class:`.Session` being maintained by the registry::
+ Session = scoped_session(some_factory)
+ # print session.query(MyClass).all()
+ print Session.query(MyClass).all()
+The above code accomplishes the same task as that of acquiring the current
+:class:`.Session` by calling upon the registry, then using that :class:`.Session`.
+Users who are familiar with multithreaded programming will note that representing
+anything as a global variable is usually a bad idea, as it implies that the
+global object will be accessed by many threads concurrently. The :class:`.Session`
+object is entirely designed to be used in a **non-concurrent** fashion, which
+in terms of multithreading means "only in one thread at a time". So our
+above example of :class:`.scoped_session` usage, where the same :class:`.Session`
+object is maintained across multiple calls, suggests that some process needs
+to be in place such that mutltiple calls across many threads don't actually get
+a handle to the same session. We call this notion **thread local storage**,
+which means, a special object is used that will maintain a distinct object
+per each application thread. Python provides this via the
+construct. The :class:`.scoped_session` object by default uses this object
+as storage, so that a single :class:`.Session` is maintained for all who call
+upon the :class:`.scoped_session` registry, but only within the scope of a single
+thread. Callers who call upon the registry in a different thread get a
+:class:`.Session` instance that is local to that other thread.
+Using this technique, the :class:`.scoped_session` provides a quick and relatively
+simple (if one is familiar with thread-local storage) way of providing
+a single, global object in an application that is safe to be called upon
+The :meth:`.scoped_session.remove` method, as always, removes the current
+:class:`.Session` associated with the thread, if any. However, one advantage of the
+``threading.local()`` object is that if the application thread itself ends, the
+"storage" for that thread is also garbage collected. So it is in fact "safe" to
+use thread local scope with an application that spawns and tears down threads,
+without the need to call :meth:`.scoped_session.remove`. However, the scope
+of transactions themselves, i.e. ending them via :meth:`.Session.commit` or
+:meth:`.Session.rollback`, will usually still be something that must be explicitly
+arranged for at the appropriate time, unless the application actually ties the
+lifespan of a thread to the lifespan of a transaction.
-Lifespan of a Contextual Session
+Using Thread-Local Scope with Web Applications
-A (really, really) common question is when does the contextual session get
-created, when does it get disposed ? We'll consider a typical lifespan as used
+As discussed in the section :ref:`session_faq_whentocreate`, a web application
+is architected around the concept of a **web request**, and integrating
+such an application with the :class:`.Session` usually implies that the :class:`.Session`
+will be associated with that request. As it turns out, most Python web frameworks,
+with notable exceptions such as the asynchronous frameworks Twisted and
+Tornado, use threads in a simple way, such that a particular web request is received,
+processed, and completed within the scope of a single *worker thread*. When
+the request ends, the worker thread is released to a pool of workers where it
+is available to handle another request.
- Web Server Web Framework User-defined Controller Call
+This simple correspondence of web request and thread means that to associate a
+:class:`.Session` with a thread implies it is also associated with the web request
+running within that thread, and vice versa, provided that the :class:`.Session` is
+created only after the web request begins and torn down just before the web request ends.
+So it is a very common practice to use :class:`.scoped_session` as a quick way
+to integrate the :class:`.Session` with a web application. The sequence
+diagram below illustrates this flow::
+ Web Server Web Framework SQLAlchemy ORM Code
-------------- -------------- ------------------------------
- call controller -> # call Session(). this establishes a new,
+ startup -> Web framework # Session registry is established
+ initializes Session = scoped_session(sessionmaker())
- # load some objects, save some changes
- objects = session.query(MyClass).all()
+ web request -> web request -> # The registry is *optionally*
+ starts # called upon explicitly to create
+ # a Session local to the thread and/or request
- # some other code calls Session, it's the
- # same contextual session as "sess"
+ # the Session registry can otherwise
+ # be used at any time, creating the
+ # request-local Session() if not present,
+ # or returning the existing one
+ Session.query(MyClass) # ...
- # generate content to be returned
- return generate_content()
+ Session.add(some_object) # ...
-The above example illustrates an explicit call to :meth:`.ScopedSession.remove`. This
-has the effect such that each web request starts fresh with a brand new
-session, and is the most definitive approach to closing out a request.
+ # if data was modified, commit the
-It's not strictly necessary to remove the session at the end of the request -
-other options include calling :meth:`.Session.close`, :meth:`.Session.rollback`,
-:meth:`.Session.commit` at the end so that the existing session returns
-its connections to the pool and removes any existing transactional context.
-Doing nothing is an option too, if individual controller methods take responsibility
-for ensuring that no transactions remain open after a request ends.
+ web request ends -> # the registry is instructed to
+Using the above flow, the process of integrating the :class:`.Session` with the
+web application has exactly two requirements:
+1. Create a single :class:`.scoped_session` registry when the web application
+ first starts, ensuring that this object is accessible by the rest of the
+2. Ensure that :meth:`.scoped_session.remove` is called when the web request ends,
+ usually by integrating with the web framework's event system to establish
+ an "on request end" event.
+As noted earlier, the above pattern is **just one potential way** to integrate a :class:`.Session`
+with a web framework, one which in particular makes the significant assumption
+that the **web framework associates web requests with application threads**. It is
+however **strongly recommended that the integration tools provided with the web framework
+itself be used, if available**, instead of :class:`.scoped_session`.
+In particular, while using a thread local can be convenient, it is preferable that the :class:`.Session` be
+associated **directly with the request**, rather than with
+the current thread. The next section on custom scopes details a more advanced configuration
+which can combine the usage of :class:`.scoped_session` with direct request based scope, or
+Using Custom Created Scopes
+The :class:`.scoped_session` object's default behavior of "thread local" scope is only
+one of many options on how to "scope" a :class:`.Session`. A custom scope can be defined
+based on any existing system of getting at "the current thing we are working with".
+Suppose a web framework defines a library function ``get_current_request()``. An application
+build on this framework can call this function at any time, and the result will be
+some kind of ``Request`` object that represents the current request being processed.
+If the ``Request`` object is hashable, then this function can be easily integrated with
+:class:`.scoped_session` to associate the :class:`.Session` with the request. Below we illustrate
+this in conjunction with a hypothetical event marker provided by the web framework
+``on_request_end``, which allows code to be invoked whenever a request ends::
+ from my_web_framework import get_current_request, on_request_end
+ from sqlalchemy.orm import scoped_session, sessionmaker
+ Session = scoped_session(sessionmaker(bind=some_engine), scopefunc=get_current_request)
+ def remove_session(req):
+Above, we instantiate :class:`.scoped_session` in the usual way, except that we pass
+our request-returning function as the "scopefunc". This instructs :class:`.scoped_session`
+to use this function to generate a dictionary key whenever the registry is called upon
+to return the current :class:`.Session`. In this case it is particularly important
+that we ensure a reliable "remove" system is implemented, as this dictionary is not
-.. autofunction:: sqlalchemy.orm.scoped_session
-.. autoclass:: sqlalchemy.orm.scoping.ScopedSession
+.. autoclass:: sqlalchemy.orm.scoping.scoped_session
.. autoclass:: sqlalchemy.util.ScopedRegistry
The above :class:`.Session` class is plugged in using the ``class_``
-argument to :
+argument to ::`.sessionmaker`::
Session = sessionmaker(class_=RoutingSession)
Session and sessionmaker()
-.. autofunction:: sessionmaker
+.. autoclass:: sessionmaker
.. autoclass:: sqlalchemy.orm.session.Session
.. autoclass:: sqlalchemy.orm.session.SessionTransaction