2
# Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
2
# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
4
4
# This module is part of SQLAlchemy and is released under
5
5
# the MIT License: http://www.opensource.org/licenses/mit-license.php
7
6
"""Provides the Session class and related utilities."""
8
from __future__ import with_statement
10
from itertools import chain
11
from sqlalchemy import util, sql, engine, log, exc as sa_exc
12
from sqlalchemy.sql import util as sql_util, expression
13
from sqlalchemy.orm import (
14
SessionExtension, attributes, exc, query, unitofwork, util as mapperutil, state
16
from sqlalchemy.orm.util import object_mapper as _object_mapper
17
from sqlalchemy.orm.util import class_mapper as _class_mapper
18
from sqlalchemy.orm.util import (
19
_class_to_mapper, _state_mapper,
21
from sqlalchemy.orm.mapper import Mapper, _none_set
22
from sqlalchemy.orm.unitofwork import UOWTransaction
23
from sqlalchemy.orm import identity
24
from sqlalchemy import event
25
from sqlalchemy.orm.events import SessionEvents
11
from .. import util, sql, engine, exc as sa_exc, event
12
from ..sql import util as sql_util, expression
14
SessionExtension, attributes, exc, query, util as orm_util,
18
object_mapper, class_mapper,
19
_class_to_mapper, _state_mapper, object_state,
22
from .unitofwork import UOWTransaction
23
from .mapper import Mapper
24
from .events import SessionEvents
25
statelib = util.importlater("sqlalchemy.orm", "state")
29
__all__ = ['Session', 'SessionTransaction', 'SessionExtension']
32
def sessionmaker(bind=None, class_=None, autoflush=True, autocommit=False,
33
expire_on_commit=True, **kwargs):
34
"""Generate a custom-configured :class:`.Session` class.
36
The returned object is a subclass of :class:`.Session`, which, when instantiated
37
with no arguments, uses the keyword arguments configured here as its
38
constructor arguments.
40
It is intended that the :func:`.sessionmaker()` function be called within the
41
global scope of an application, and the returned class be made available
42
to the rest of the application as the single class used to instantiate
48
Session = sessionmaker(autoflush=False)
50
# later, in a local scope, create and use a session:
53
Any keyword arguments sent to the constructor itself will override the
54
"configured" keywords::
56
Session = sessionmaker()
58
# bind an individual session to a connection
59
sess = Session(bind=connection)
61
The class also includes a special classmethod ``configure()``, which
62
allows additional configurational options to take place after the custom
63
``Session`` class has been generated. This is useful particularly for
64
defining the specific ``Engine`` (or engines) to which new instances of
65
``Session`` should be bound::
67
Session = sessionmaker()
68
Session.configure(bind=create_engine('sqlite:///foo.db'))
72
For options, see the constructor options for :class:`.Session`.
76
kwargs['autoflush'] = autoflush
77
kwargs['autocommit'] = autocommit
78
kwargs['expire_on_commit'] = expire_on_commit
84
def __init__(self, **local_kwargs):
86
local_kwargs.setdefault(k, kwargs[k])
87
super(Sess, self).__init__(**local_kwargs)
90
def configure(self, **new_kwargs):
91
"""(Re)configure the arguments for this sessionmaker.
95
Session = sessionmaker()
97
Session.configure(bind=create_engine('sqlite://'))
99
kwargs.update(new_kwargs)
102
return type("SessionMaker", (Sess, class_), {})
28
__all__ = ['Session', 'SessionTransaction', 'SessionExtension', 'sessionmaker']
31
class _SessionClassMethods(object):
32
"""Class-level methods for :class:`.Session`, :class:`.sessionmaker`."""
36
"""Close *all* sessions in memory."""
38
for sess in _sessions.values():
42
def identity_key(cls, *args, **kwargs):
43
"""Return an identity key.
45
This is an alias of :func:`.util.identity_key`.
48
return orm_util.identity_key(*args, **kwargs)
51
def object_session(cls, instance):
52
"""Return the :class:`.Session` to which an object belongs.
54
This is an alias of :func:`.object_session`.
58
return object_session(instance)
61
ACTIVE = util.symbol('ACTIVE')
62
PREPARED = util.symbol('PREPARED')
63
COMMITTED = util.symbol('COMMITTED')
64
DEACTIVE = util.symbol('DEACTIVE')
65
CLOSED = util.symbol('CLOSED')
105
67
class SessionTransaction(object):
106
68
"""A :class:`.Session`-level transaction.
112
74
back all at once. It also provides optional two-phase commit behavior
113
75
which can augment this coordination operation.
115
The :attr:`.Session.transaction` attribute of :class:`.Session` refers to the
116
current :class:`.SessionTransaction` object in use, if any.
77
The :attr:`.Session.transaction` attribute of :class:`.Session`
78
refers to the current :class:`.SessionTransaction` object in use, if any.
119
81
A :class:`.SessionTransaction` is associated with a :class:`.Session`
120
82
in its default mode of ``autocommit=False`` immediately, associated
121
83
with no database connections. As the :class:`.Session` is called upon
122
84
to emit SQL on behalf of various :class:`.Engine` or :class:`.Connection`
123
objects, a corresponding :class:`.Connection` and associated :class:`.Transaction`
124
is added to a collection within the :class:`.SessionTransaction` object,
125
becoming one of the connection/transaction pairs maintained by the
85
objects, a corresponding :class:`.Connection` and associated
86
:class:`.Transaction` is added to a collection within the
87
:class:`.SessionTransaction` object, becoming one of the
88
connection/transaction pairs maintained by the
126
89
:class:`.SessionTransaction`.
128
91
The lifespan of the :class:`.SessionTransaction` ends when the
129
:meth:`.Session.commit`, :meth:`.Session.rollback` or :meth:`.Session.close`
130
methods are called. At this point, the :class:`.SessionTransaction` removes
131
its association with its parent :class:`.Session`. A :class:`.Session`
132
that is in ``autocommit=False`` mode will create a new
133
:class:`.SessionTransaction` to replace it immediately, whereas a
134
:class:`.Session` that's in ``autocommit=True``
92
:meth:`.Session.commit`, :meth:`.Session.rollback` or
93
:meth:`.Session.close` methods are called. At this point, the
94
:class:`.SessionTransaction` removes its association with its parent
95
:class:`.Session`. A :class:`.Session` that is in ``autocommit=False``
96
mode will create a new :class:`.SessionTransaction` to replace it
97
immediately, whereas a :class:`.Session` that's in ``autocommit=True``
135
98
mode will remain without a :class:`.SessionTransaction` until the
136
99
:meth:`.Session.begin` method is called.
138
101
Another detail of :class:`.SessionTransaction` behavior is that it is
139
capable of "nesting". This means that the :meth:`.begin` method can
140
be called while an existing :class:`.SessionTransaction` is already present,
141
producing a new :class:`.SessionTransaction` that temporarily replaces
142
the parent :class:`.SessionTransaction`. When a :class:`.SessionTransaction`
143
is produced as nested, it assigns itself to the :attr:`.Session.transaction`
144
attribute. When it is ended via :meth:`.Session.commit` or :meth:`.Session.rollback`,
145
it restores its parent :class:`.SessionTransaction` back onto the
146
:attr:`.Session.transaction` attribute. The
147
behavior is effectively a stack, where :attr:`.Session.transaction` refers
148
to the current head of the stack.
102
capable of "nesting". This means that the :meth:`.Session.begin` method
103
can be called while an existing :class:`.SessionTransaction` is already
104
present, producing a new :class:`.SessionTransaction` that temporarily
105
replaces the parent :class:`.SessionTransaction`. When a
106
:class:`.SessionTransaction` is produced as nested, it assigns itself to
107
the :attr:`.Session.transaction` attribute. When it is ended via
108
:meth:`.Session.commit` or :meth:`.Session.rollback`, it restores its
109
parent :class:`.SessionTransaction` back onto the
110
:attr:`.Session.transaction` attribute. The behavior is effectively a
111
stack, where :attr:`.Session.transaction` refers to the current head of
150
The purpose of this stack is to allow nesting of :meth:`.rollback` or
151
:meth:`.commit` calls in context with various flavors of :meth:`.begin`.
152
This nesting behavior applies to when :meth:`.Session.begin_nested`
153
is used to emit a SAVEPOINT transaction, and is also used to produce
154
a so-called "subtransaction" which allows a block of code to use a
114
The purpose of this stack is to allow nesting of
115
:meth:`.Session.rollback` or :meth:`.Session.commit` calls in context
116
with various flavors of :meth:`.Session.begin`. This nesting behavior
117
applies to when :meth:`.Session.begin_nested` is used to emit a
118
SAVEPOINT transaction, and is also used to produce a so-called
119
"subtransaction" which allows a block of code to use a
155
120
begin/rollback/commit sequence regardless of whether or not its enclosing
156
code block has begun a transaction. The :meth:`.flush` method, whether called
157
explicitly or via autoflush, is the primary consumer of the "subtransaction"
158
feature, in that it wishes to guarantee that it works within in a transaction block
159
regardless of whether or not the :class:`.Session` is in transactional mode
160
when the method is called.
121
code block has begun a transaction. The :meth:`.flush` method, whether
122
called explicitly or via autoflush, is the primary consumer of the
123
"subtransaction" feature, in that it wishes to guarantee that it works
124
within in a transaction block regardless of whether or not the
125
:class:`.Session` is in transactional mode when the method is called.
196
160
if self.session._enable_transaction_accounting:
197
161
self._take_snapshot()
163
if self.session.dispatch.after_transaction_create:
164
self.session.dispatch.after_transaction_create(self.session, self)
200
167
def is_active(self):
201
return self.session is not None and self._active
168
return self.session is not None and self._state is ACTIVE
203
def _assert_is_active(self):
204
self._assert_is_open()
206
if self._rollback_exception:
207
raise sa_exc.InvalidRequestError(
208
"This Session's transaction has been rolled back "
209
"due to a previous exception during flush."
210
" To begin a new transaction with this Session, "
211
"first issue Session.rollback()."
212
" Original exception was: %s"
213
% self._rollback_exception
170
def _assert_active(self, prepared_ok=False,
173
closed_msg="This transaction is closed"):
174
if self._state is COMMITTED:
175
raise sa_exc.InvalidRequestError(
176
"This session is in 'committed' state; no further "
177
"SQL can be emitted within this transaction."
179
elif self._state is PREPARED:
216
181
raise sa_exc.InvalidRequestError(
217
"This Session's transaction has been rolled back "
218
"by a nested rollback() call. To begin a new "
219
"transaction, issue Session.rollback() first."
222
def _assert_is_open(self, error_msg="The transaction is closed"):
223
if self.session is None:
224
raise sa_exc.ResourceClosedError(error_msg)
182
"This session is in 'prepared' state; no further "
183
"SQL can be emitted within this transaction."
185
elif self._state is DEACTIVE:
186
if not deactive_ok and not rollback_ok:
187
if self._rollback_exception:
188
raise sa_exc.InvalidRequestError(
189
"This Session's transaction has been rolled back "
190
"due to a previous exception during flush."
191
" To begin a new transaction with this Session, "
192
"first issue Session.rollback()."
193
" Original exception was: %s"
194
% self._rollback_exception
196
elif not deactive_ok:
197
raise sa_exc.InvalidRequestError(
198
"This Session's transaction has been rolled back "
199
"by a nested rollback() call. To begin a new "
200
"transaction, issue Session.rollback() first."
202
elif self._state is CLOSED:
203
raise sa_exc.ResourceClosedError(closed_msg)
227
206
def _is_transaction_boundary(self):
228
207
return self.nested or not self._parent
230
209
def connection(self, bindkey, **kwargs):
231
self._assert_is_active()
232
engine = self.session.get_bind(bindkey, **kwargs)
233
return self._connection_for_bind(engine)
210
self._assert_active()
211
bind = self.session.get_bind(bindkey, **kwargs)
212
return self._connection_for_bind(bind)
235
214
def _begin(self, nested=False):
236
self._assert_is_active()
215
self._assert_active()
237
216
return SessionTransaction(
238
217
self.session, self, nested=nested)
253
for s, (oldkey, newkey) in self._key_switches.items():
254
self.session.identity_map.discard(s)
256
self.session.identity_map.replace(s)
270
258
for s in set(self._deleted).union(self.session._deleted):
272
260
#assert s in self._deleted
274
self.session._update_impl(s)
262
self.session._update_impl(s, discard_existing=True)
276
264
assert not self.session._deleted
278
266
for s in self.session.identity_map.all_states():
279
s.expire(s.dict, self.session.identity_map._modified)
267
if not dirty_only or s.modified or s in self._dirty:
268
s._expire(s.dict, self.session.identity_map._modified)
281
270
def _remove_snapshot(self):
282
271
assert self._is_transaction_boundary
284
273
if not self.nested and self.session.expire_on_commit:
285
274
for s in self.session.identity_map.all_states():
286
s.expire(s.dict, self.session.identity_map._modified)
275
s._expire(s.dict, self.session.identity_map._modified)
276
for s in self._deleted:
278
self._deleted.clear()
288
281
def _connection_for_bind(self, bind):
289
self._assert_is_active()
282
self._assert_active()
291
284
if bind in self._connections:
292
285
return self._connections[bind][0]
373
367
return self._parent
375
369
def rollback(self, _capture_exception=False):
376
self._assert_is_open()
370
self._assert_active(prepared_ok=True, rollback_ok=True)
378
372
stx = self.session.transaction
379
373
if stx is not self:
380
374
for subtransaction in stx._iterate_parents(upto=self):
381
375
subtransaction.close()
383
if self.is_active or self._prepared:
377
if self._state in (ACTIVE, PREPARED):
384
378
for transaction in self._iterate_parents():
385
379
if transaction._parent is None or transaction.nested:
386
380
transaction._rollback_impl()
387
transaction._deactivate()
381
transaction._state = DEACTIVE
390
transaction._deactivate()
384
transaction._state = DEACTIVE
392
386
sess = self.session
394
388
if self.session._enable_transaction_accounting and \
395
not sess._is_clean():
389
not sess._is_clean():
396
390
# if items were added, deleted, or mutated
397
391
# here, we need to re-restore the snapshot
399
393
"Session's state has been changed on "
400
394
"a non-active transaction - this state "
401
395
"will be discarded.")
402
self._restore_snapshot()
396
self._restore_snapshot(dirty_only=self.nested)
405
399
if self._parent and _capture_exception:
477
472
query_cls=query.Query):
478
473
"""Construct a new Session.
480
See also the :func:`.sessionmaker` function which is used to
475
See also the :class:`.sessionmaker` function which is used to
481
476
generate a :class:`.Session`-producing callable with a given
482
477
set of arguments.
484
:param autocommit: Defaults to ``False``. When ``True``, the ``Session``
485
does not keep a persistent transaction running, and will acquire
486
connections from the engine on an as-needed basis, returning them
487
immediately after their use. Flushes will begin and commit (or possibly
488
rollback) their own transaction if no transaction is present. When using
489
this mode, the `session.begin()` method may be used to begin a
490
transaction explicitly.
492
Leaving it on its default value of ``False`` means that the ``Session``
493
will acquire a connection and begin a transaction the first time it is
494
used, which it will maintain persistently until ``rollback()``,
495
``commit()``, or ``close()`` is called. When the transaction is released
496
by any of these methods, the ``Session`` is ready for the next usage,
497
which will again acquire and maintain a new connection/transaction.
483
The autocommit flag is **not for general use**, and if it is used,
484
queries should only be invoked within the span of a
485
:meth:`.Session.begin` / :meth:`.Session.commit` pair. Executing
486
queries outside of a demarcated transaction is a legacy mode
487
of usage, and can in some cases lead to concurrent connection
490
Defaults to ``False``. When ``True``, the
491
:class:`.Session` does not keep a persistent transaction running, and
492
will acquire connections from the engine on an as-needed basis,
493
returning them immediately after their use. Flushes will begin and
494
commit (or possibly rollback) their own transaction if no
495
transaction is present. When using this mode, the
496
:meth:`.Session.begin` method is used to explicitly start
501
:ref:`session_autocommit`
499
503
:param autoflush: When ``True``, all query operations will issue a
500
504
``flush()`` call to this ``Session`` before proceeding. This is a
501
convenience feature so that ``flush()`` need not be called repeatedly
502
in order for database queries to retrieve results. It's typical that
503
``autoflush`` is used in conjunction with ``autocommit=False``. In this
504
scenario, explicit calls to ``flush()`` are rarely needed; you usually
505
only need to call ``commit()`` (which flushes) to finalize changes.
505
convenience feature so that ``flush()`` need not be called
506
repeatedly in order for database queries to retrieve results. It's
507
typical that ``autoflush`` is used in conjunction with
508
``autocommit=False``. In this scenario, explicit calls to
509
``flush()`` are rarely needed; you usually only need to call
510
``commit()`` (which flushes) to finalize changes.
507
512
:param bind: An optional ``Engine`` or ``Connection`` to which this
508
513
``Session`` should be bound. When specified, all SQL operations
509
514
performed by this session will execute via this connectable.
511
:param binds: An optional dictionary which contains more granular "bind"
512
information than the ``bind`` parameter provides. This dictionary can
513
map individual ``Table`` instances as well as ``Mapper`` instances to
514
individual ``Engine`` or ``Connection`` objects. Operations which
515
proceed relative to a particular ``Mapper`` will consult this
516
dictionary for the direct ``Mapper`` instance as well as the mapper's
517
``mapped_table`` attribute in order to locate an connectable to use.
518
The full resolution is described in the ``get_bind()`` method of
519
``Session``. Usage looks like::
516
:param binds: An optional dictionary which contains more granular
517
"bind" information than the ``bind`` parameter provides. This
518
dictionary can map individual ``Table`` instances as well as
519
``Mapper`` instances to individual ``Engine`` or ``Connection``
520
objects. Operations which proceed relative to a particular
521
``Mapper`` will consult this dictionary for the direct ``Mapper``
522
instance as well as the mapper's ``mapped_table`` attribute in
523
order to locate an connectable to use. The full resolution is
524
described in the ``get_bind()`` method of ``Session``.
521
527
Session = sessionmaker(binds={
522
528
SomeMappedClass: create_engine('postgresql://engine1'),
524
530
some_table: create_engine('postgresql://engine3'),
527
Also see the :meth:`.Session.bind_mapper` and :meth:`.Session.bind_table` methods.
533
Also see the :meth:`.Session.bind_mapper`
534
and :meth:`.Session.bind_table` methods.
529
536
:param \class_: Specify an alternate class other than
530
``sqlalchemy.orm.session.Session`` which should be used by the returned
531
class. This is the only argument that is local to the
537
``sqlalchemy.orm.session.Session`` which should be used by the
538
returned class. This is the only argument that is local to the
532
539
``sessionmaker()`` function, and is not sent directly to the
533
540
constructor for ``Session``.
535
542
:param _enable_transaction_accounting: Defaults to ``True``. A
536
legacy-only flag which when ``False`` disables *all* 0.5-style object
537
accounting on transaction boundaries, including auto-expiry of
538
instances on rollback and commit, maintenance of the "new" and
543
legacy-only flag which when ``False`` disables *all* 0.5-style
544
object accounting on transaction boundaries, including auto-expiry
545
of instances on rollback and commit, maintenance of the "new" and
539
546
"deleted" lists upon rollback, and autoflush of pending changes upon
540
547
begin(), all of which are interdependent.
542
549
:param expire_on_commit: Defaults to ``True``. When ``True``, all
543
instances will be fully expired after each ``commit()``, so that all
544
attribute/object access subsequent to a completed transaction will load
545
from the most recent database state.
550
instances will be fully expired after each ``commit()``, so that
551
all attribute/object access subsequent to a completed transaction
552
will load from the most recent database state.
547
554
:param extension: An optional
548
555
:class:`~.SessionExtension` instance, or a list
549
of such instances, which will receive pre- and post- commit and flush
550
events, as well as a post-rollback event. **Deprecated.**
556
of such instances, which will receive pre- and post- commit and
557
flush events, as well as a post-rollback event. **Deprecated.**
551
558
Please see :class:`.SessionEvents`.
553
:param query_cls: Class which should be used to create new Query objects,
554
as returned by the ``query()`` method. Defaults to
560
:param query_cls: Class which should be used to create new Query
561
objects, as returned by the ``query()`` method. Defaults to
555
562
:class:`~sqlalchemy.orm.query.Query`.
557
564
:param twophase: When ``True``, all transactions will be started as
558
565
a "two phase" transaction, i.e. using the "two phase" semantics
559
566
of the database in use along with an XID. During a ``commit()``,
560
567
after ``flush()`` has been issued for all attached databases, the
561
``prepare()`` method on each database's ``TwoPhaseTransaction`` will
562
be called. This allows each database to roll back the entire
568
``prepare()`` method on each database's ``TwoPhaseTransaction``
569
will be called. This allows each database to roll back the entire
563
570
transaction, before each transaction is committed.
565
572
:param weak_identity_map: Defaults to ``True`` - when set to
621
629
transaction or nested transaction, an error is raised, unless
622
630
``subtransactions=True`` or ``nested=True`` is specified.
624
The ``subtransactions=True`` flag indicates that this :meth:`~.Session.begin`
625
can create a subtransaction if a transaction is already in progress.
626
For documentation on subtransactions, please see :ref:`session_subtransactions`.
632
The ``subtransactions=True`` flag indicates that this
633
:meth:`~.Session.begin` can create a subtransaction if a transaction
634
is already in progress. For documentation on subtransactions, please
635
see :ref:`session_subtransactions`.
628
637
The ``nested`` flag begins a SAVEPOINT transaction and is equivalent
629
to calling :meth:`~.Session.begin_nested`. For documentation on SAVEPOINT
630
transactions, please see :ref:`session_begin_nested`.
638
to calling :meth:`~.Session.begin_nested`. For documentation on
639
SAVEPOINT transactions, please see :ref:`session_begin_nested`.
633
642
if self.transaction is not None:
675
688
"""Flush pending changes and commit the current transaction.
677
690
If no transaction is in progress, this method raises an
691
:exc:`~sqlalchemy.exc.InvalidRequestError`.
680
693
By default, the :class:`.Session` also expires all database
681
694
loaded state on all ORM-managed attributes after transaction commit.
682
695
This so that subsequent operations load the most recent
683
696
data from the database. This behavior can be disabled using
684
the ``expire_on_commit=False`` option to :func:`.sessionmaker` or
697
the ``expire_on_commit=False`` option to :class:`.sessionmaker` or
685
698
the :class:`.Session` constructor.
687
700
If a subtransaction is in effect (which occurs when begin() is called
688
701
multiple times), the subtransaction will be closed, and the next call
689
702
to ``commit()`` will operate on the enclosing transaction.
691
For a session configured with autocommit=False, a new transaction will
704
When using the :class:`.Session` in its default mode of
705
``autocommit=False``, a new transaction will
692
706
be begun immediately after the commit, but note that the newly begun
693
707
transaction does *not* use any connection resources until the first
694
708
SQL is actually emitted.
712
:ref:`session_committing`
697
715
if self.transaction is None:
698
716
if not self.autocommit:
728
747
:class:`.Session` object's transactional state.
730
749
If this :class:`.Session` is configured with ``autocommit=False``,
731
either the :class:`.Connection` corresponding to the current transaction
732
is returned, or if no transaction is in progress, a new one is begun
733
and the :class:`.Connection` returned (note that no transactional state
734
is established with the DBAPI until the first SQL statement is emitted).
736
Alternatively, if this :class:`.Session` is configured with ``autocommit=True``,
737
an ad-hoc :class:`.Connection` is returned using :meth:`.Engine.contextual_connect`
738
on the underlying :class:`.Engine`.
740
Ambiguity in multi-bind or unbound :class:`.Session` objects can be resolved through
741
any of the optional keyword arguments. This ultimately makes usage of the
742
:meth:`.get_bind` method for resolution.
750
either the :class:`.Connection` corresponding to the current
751
transaction is returned, or if no transaction is in progress, a new
752
one is begun and the :class:`.Connection` returned (note that no
753
transactional state is established with the DBAPI until the first
754
SQL statement is emitted).
756
Alternatively, if this :class:`.Session` is configured with
757
``autocommit=True``, an ad-hoc :class:`.Connection` is returned
758
using :meth:`.Engine.contextual_connect` on the underlying
761
Ambiguity in multi-bind or unbound :class:`.Session` objects can be
762
resolved through any of the optional keyword arguments. This
763
ultimately makes usage of the :meth:`.get_bind` method for resolution.
745
766
Optional :class:`.Engine` to be used as the bind. If
852
875
The :class:`.ResultProxy` returned by the :meth:`.Session.execute`
853
876
method is returned with the "close_with_result" flag set to true;
854
877
the significance of this flag is that if this :class:`.Session` is
855
autocommitting and does not have a transaction-dedicated :class:`.Connection`
856
available, a temporary :class:`.Connection` is established for the
857
statement execution, which is closed (meaning, returned to the connection
858
pool) when the :class:`.ResultProxy` has consumed all available data.
859
This applies *only* when the :class:`.Session` is configured with
860
autocommit=True and no transaction has been started.
878
autocommitting and does not have a transaction-dedicated
879
:class:`.Connection` available, a temporary :class:`.Connection` is
880
established for the statement execution, which is closed (meaning,
881
returned to the connection pool) when the :class:`.ResultProxy` has
882
consumed all available data. This applies *only* when the
883
:class:`.Session` is configured with autocommit=True and no
884
transaction has been started.
863
887
An executable statement (i.e. an :class:`.Executable` expression
1286
1302
def _expunge_state(self, state):
1287
1303
if state in self._new:
1288
1304
self._new.pop(state)
1290
1306
elif self.identity_map.contains_state(state):
1291
1307
self.identity_map.discard(state)
1292
1308
self._deleted.pop(state, None)
1294
1310
elif self.transaction:
1295
1311
self.transaction._deleted.pop(state, None)
1297
def _register_newly_persistent(self, state):
1298
mapper = _state_mapper(state)
1300
# prevent against last minute dereferences of the object
1304
instance_key = mapper._identity_key_from_state(state)
1306
if _none_set.issubset(instance_key[1]) and \
1307
not mapper.allow_partial_pks or \
1308
_none_set.issuperset(instance_key[1]):
1309
raise exc.FlushError(
1310
"Instance %s has a NULL identity key. If this is an "
1311
"auto-generated value, check that the database table "
1312
"allows generation of new primary key values, and that "
1313
"the mapped Column object is configured to expect these "
1314
"generated values. Ensure also that this flush() is "
1315
"not occurring at an inappropriate time, such as within "
1316
"a load() event." % mapperutil.state_str(state)
1319
if state.key is None:
1320
state.key = instance_key
1321
elif state.key != instance_key:
1322
# primary key switch. use discard() in case another
1323
# state has already replaced this one in the identity
1324
# map (see test/orm/test_naturalpks.py ReversePKsTest)
1325
self.identity_map.discard(state)
1326
state.key = instance_key
1328
self.identity_map.replace(state)
1329
state.commit_all(state.dict, self.identity_map)
1313
def _register_newly_persistent(self, states):
1314
for state in states:
1315
mapper = _state_mapper(state)
1317
# prevent against last minute dereferences of the object
1321
instance_key = mapper._identity_key_from_state(state)
1323
if _none_set.issubset(instance_key[1]) and \
1324
not mapper.allow_partial_pks or \
1325
_none_set.issuperset(instance_key[1]):
1326
raise exc.FlushError(
1327
"Instance %s has a NULL identity key. If this is an "
1328
"auto-generated value, check that the database table "
1329
"allows generation of new primary key values, and "
1330
"that the mapped Column object is configured to "
1331
"expect these generated values. Ensure also that "
1332
"this flush() is not occurring at an inappropriate "
1333
"time, such aswithin a load() event."
1334
% orm_util.state_str(state)
1337
if state.key is None:
1338
state.key = instance_key
1339
elif state.key != instance_key:
1340
# primary key switch. use discard() in case another
1341
# state has already replaced this one in the identity
1342
# map (see test/orm/test_naturalpks.py ReversePKsTest)
1343
self.identity_map.discard(state)
1344
if state in self.transaction._key_switches:
1345
orig_key = self.transaction._key_switches[state][0]
1347
orig_key = state.key
1348
self.transaction._key_switches[state] = (
1349
orig_key, instance_key)
1350
state.key = instance_key
1352
self.identity_map.replace(state)
1354
statelib.InstanceState._commit_all_states(
1355
((state, state.dict) for state in states),
1359
self._register_altered(states)
1331
1360
# remove from new last, might be the last strong ref
1332
if state in self._new:
1361
for state in set(states).intersection(self._new):
1362
self._new.pop(state)
1364
def _register_altered(self, states):
1365
if self._enable_transaction_accounting and self.transaction:
1366
for state in states:
1367
if state in self._new:
1368
self.transaction._new[state] = True
1370
self.transaction._dirty[state] = True
1372
def _remove_newly_deleted(self, states):
1373
for state in states:
1333
1374
if self._enable_transaction_accounting and self.transaction:
1334
self.transaction._new[state] = True
1335
self._new.pop(state)
1337
def _remove_newly_deleted(self, state):
1338
if self._enable_transaction_accounting and self.transaction:
1339
self.transaction._deleted[state] = True
1341
self.identity_map.discard(state)
1342
self._deleted.pop(state, None)
1343
state.deleted = True
1345
def add(self, instance):
1375
self.transaction._deleted[state] = True
1377
self.identity_map.discard(state)
1378
self._deleted.pop(state, None)
1379
state.deleted = True
1381
def add(self, instance, _warn=True):
1346
1382
"""Place an object in the ``Session``.
1348
1384
Its state will be persisted to the database on the next flush
1570
1614
# remove any history
1571
merged_state.commit_all(merged_dict, self.identity_map)
1615
merged_state._commit_all(merged_dict, self.identity_map)
1573
1617
if new_instance:
1574
1618
merged_state.manager.dispatch.load(merged_state, None)
1578
def identity_key(cls, *args, **kwargs):
1579
return mapperutil.identity_key(*args, **kwargs)
1582
def object_session(cls, instance):
1583
"""Return the ``Session`` to which an object belongs."""
1585
return object_session(instance)
1587
1621
def _validate_persistent(self, state):
1588
1622
if not self.identity_map.contains_state(state):
1589
1623
raise sa_exc.InvalidRequestError(
1590
1624
"Instance '%s' is not persistent within this Session" %
1591
mapperutil.state_str(state))
1625
orm_util.state_str(state))
1593
1627
def _save_impl(self, state):
1594
1628
if state.key is not None:
1595
1629
raise sa_exc.InvalidRequestError(
1596
1630
"Object '%s' already has an identity - it can't be registered "
1597
"as pending" % mapperutil.state_str(state))
1631
"as pending" % orm_util.state_str(state))
1633
self._before_attach(state)
1600
1634
if state not in self._new:
1601
1635
self._new[state] = state.obj()
1602
1636
state.insert_order = len(self._new)
1604
def _update_impl(self, state):
1639
def _update_impl(self, state, discard_existing=False):
1605
1640
if (self.identity_map.contains_state(state) and
1606
1641
state not in self._deleted):
1634
1673
if state.key is None:
1676
self._attach(state, include_before=True)
1638
1677
self._deleted[state] = state.obj()
1639
1678
self.identity_map.add(state)
1641
def _attach(self, state):
1680
def enable_relationship_loading(self, obj):
1681
"""Associate an object with this :class:`.Session` for related
1686
:meth:`.enable_relationship_loading` exists to serve special
1687
use cases and is not recommended for general use.
1689
Accesses of attributes mapped with :func:`.relationship`
1690
will attempt to load a value from the database using this
1691
:class:`.Session` as the source of connectivity. The values
1692
will be loaded based on foreign key values present on this
1693
object - it follows that this functionality
1694
generally only works for many-to-one-relationships.
1696
The object will be attached to this session, but will
1697
**not** participate in any persistence operations; its state
1698
for almost all purposes will remain either "transient" or
1699
"detached", except for the case of relationship loading.
1701
Also note that backrefs will often not work as expected.
1702
Altering a relationship-bound attribute on the target object
1703
may not fire off a backref event, if the effective value
1704
is what was already loaded from a foreign-key-holding value.
1706
The :meth:`.Session.enable_relationship_loading` method supersedes
1707
the ``load_on_pending`` flag on :func:`.relationship`. Unlike
1708
that flag, :meth:`.Session.enable_relationship_loading` allows
1709
an object to remain transient while still being able to load
1712
To make a transient object associated with a :class:`.Session`
1713
via :meth:`.Session.enable_relationship_loading` pending, add
1714
it to the :class:`.Session` using :meth:`.Session.add` normally.
1716
:meth:`.Session.enable_relationship_loading` does not improve
1717
behavior when the ORM is used normally - object references should be
1718
constructed at the object level, not at the foreign key level, so
1719
that they are present in an ordinary way before flush()
1720
proceeds. This method is not intended for general use.
1722
.. versionadded:: 0.8
1725
state = attributes.instance_state(obj)
1726
self._attach(state, include_before=True)
1727
state._load_pending = True
1729
def _before_attach(self, state):
1730
if state.session_id != self.hash_key and \
1731
self.dispatch.before_attach:
1732
self.dispatch.before_attach(self, state.obj())
1734
def _attach(self, state, include_before=False):
1642
1735
if state.key and \
1643
1736
state.key in self.identity_map and \
1644
not self.identity_map.contains_state(state):
1737
not self.identity_map.contains_state(state):
1645
1738
raise sa_exc.InvalidRequestError("Can't attach instance "
1646
1739
"%s; another instance with key %s is already "
1647
1740
"present in this session."
1648
% (mapperutil.state_str(state), state.key))
1741
% (orm_util.state_str(state), state.key))
1650
1743
if state.session_id and \
1651
1744
state.session_id is not self.hash_key and \
1652
1745
state.session_id in _sessions:
1653
1746
raise sa_exc.InvalidRequestError(
1654
1747
"Object '%s' is already attached to session '%s' "
1655
"(this is '%s')" % (mapperutil.state_str(state),
1748
"(this is '%s')" % (orm_util.state_str(state),
1656
1749
state.session_id, self.hash_key))
1658
1751
if state.session_id != self.hash_key:
1752
if include_before and \
1753
self.dispatch.before_attach:
1754
self.dispatch.before_attach(self, state.obj())
1659
1755
state.session_id = self.hash_key
1756
if state.modified and state._strong_obj is None:
1757
state._strong_obj = state.obj()
1660
1758
if self.dispatch.after_attach:
1661
1759
self.dispatch.after_attach(self, state.obj())
1786
1895
flush_context.transaction = transaction = self.begin(
1787
1896
subtransactions=True)
1789
flush_context.execute()
1898
self._warn_on_events = True
1900
flush_context.execute()
1902
self._warn_on_events = False
1791
1904
self.dispatch.after_flush(self, flush_context)
1793
1906
flush_context.finalize_flush_changes()
1908
if not objects and self.identity_map._modified:
1909
len_ = len(self.identity_map._modified)
1911
statelib.InstanceState._commit_all_states(
1912
[(state, state.dict) for state in
1913
self.identity_map._modified],
1914
instance_dict=self.identity_map)
1915
util.warn("Attribute history events accumulated on %d "
1916
"previously clean instances "
1917
"within inner-flush event handlers have been reset, "
1918
"and will not result in database updates. "
1919
"Consider using set_committed_value() within "
1920
"inner-flush event handlers to avoid this warning."
1795
1923
# useful assertions:
1796
1924
#if not objects:
1797
1925
# assert not self.identity_map._modified
1827
return session.is_modified(someobject, passive=True)
1954
return session.is_modified(someobject)
1829
1956
.. versionchanged:: 0.8
1830
In SQLAlchemy 0.7 and earlier, the ``passive``
1831
flag should **always** be explicitly set to ``True``.
1832
The current default value of :data:`.attributes.PASSIVE_OFF`
1833
for this flag is incorrect, in that it loads unloaded
1834
collections and attributes which by definition
1835
have no modified state, and furthermore trips off
1836
autoflush which then causes all subsequent, possibly
1837
modified attributes to lose their modified state.
1838
The default value of the flag will be changed in 0.8.
1957
When using SQLAlchemy 0.7 and earlier, the ``passive``
1958
flag should **always** be explicitly set to ``True``,
1959
else SQL loads/autoflushes may proceed which can affect
1960
the modified state itself:
1961
``session.is_modified(someobject, passive=True)``\ .
1962
In 0.8 and above, the behavior is corrected and
1963
this flag is ignored.
1840
1965
A few caveats to this method apply:
1856
1981
usually needed, and in those few cases where it isn't, is less
1857
1982
expensive on average than issuing a defensive SELECT.
1859
The "old" value is fetched unconditionally only if the attribute
1860
container has the ``active_history`` flag set to ``True``. This flag
1861
is set typically for primary key attributes and scalar object references
1862
that are not a simple many-to-one. To set this flag for
1863
any arbitrary mapped column, use the ``active_history`` argument
1864
with :func:`.column_property`.
1984
The "old" value is fetched unconditionally upon set only if the
1985
attribute container has the ``active_history`` flag set to ``True``.
1986
This flag is set typically for primary key attributes and scalar
1987
object references that are not a simple many-to-one. To set this
1988
flag for any arbitrary mapped column, use the ``active_history``
1989
argument with :func:`.column_property`.
1866
1991
:param instance: mapped instance to be tested for pending changes.
1867
:param include_collections: Indicates if multivalued collections should be
1868
included in the operation. Setting this to ``False`` is a way to detect
1869
only local-column based properties (i.e. scalar columns or many-to-one
1870
foreign keys) that would result in an UPDATE for this instance upon
1872
:param passive: Indicates if unloaded attributes and
1873
collections should be loaded in the course of performing
1874
this test. If set to ``False``, or left at its default
1875
value of :data:`.PASSIVE_OFF`, unloaded attributes
1876
will be loaded. If set to ``True`` or
1877
:data:`.PASSIVE_NO_INITIALIZE`, unloaded
1878
collections and attributes will remain unloaded. As
1879
noted previously, the existence of this flag here
1880
is a bug, as unloaded attributes by definition have
1881
no changes, and the load operation also triggers an
1882
autoflush which then cancels out subsequent changes.
1883
This flag should **always be set to True**.
1992
:param include_collections: Indicates if multivalued collections
1993
should be included in the operation. Setting this to ``False`` is a
1994
way to detect only local-column based properties (i.e. scalar columns
1995
or many-to-one foreign keys) that would result in an UPDATE for this
1996
instance upon flush.
1885
1998
.. versionchanged:: 0.8
1886
The flag will be deprecated and the default
1999
Ignored for backwards compatibility.
2000
When using SQLAlchemy 0.7 and earlier, this flag should always
1891
state = attributes.instance_state(instance)
1892
except exc.NO_STATE:
1893
raise exc.UnmappedInstanceError(instance)
2004
state = object_state(instance)
2006
if not state.modified:
1894
2009
dict_ = state.dict
1897
passive = attributes.PASSIVE_NO_INITIALIZE
1898
elif passive is False:
1899
passive = attributes.PASSIVE_OFF
1901
2011
for attr in state.manager.attributes:
1937
2049
target :class:`.Connection` to a user-defined event listener.
1939
2051
The "partial rollback" state refers to when an "inner" transaction,
1940
typically used during a flush, encounters an error and emits
1941
a rollback of the DBAPI connection. At this point, the :class:`.Session`
1942
is in "partial rollback" and awaits for the user to call :meth:`.rollback`,
1943
in order to close out the transaction stack. It is in this "partial
1944
rollback" period that the :attr:`.is_active` flag returns False. After
1945
the call to :meth:`.rollback`, the :class:`.SessionTransaction` is replaced
2052
typically used during a flush, encounters an error and emits a
2053
rollback of the DBAPI connection. At this point, the
2054
:class:`.Session` is in "partial rollback" and awaits for the user to
2055
call :meth:`.Session.rollback`, in order to close out the
2056
transaction stack. It is in this "partial rollback" period that the
2057
:attr:`.is_active` flag returns False. After the call to
2058
:meth:`.Session.rollback`, the :class:`.SessionTransaction` is replaced
1946
2059
with a new one and :attr:`.is_active` returns ``True`` again.
1948
2061
When a :class:`.Session` is used in ``autocommit=True`` mode, the
1949
2062
:class:`.SessionTransaction` is only instantiated within the scope
1950
2063
of a flush call, or when :meth:`.Session.begin` is called. So
1951
2064
:attr:`.is_active` will always be ``False`` outside of a flush or
1952
:meth:`.begin` block in this mode, and will be ``True`` within the
1953
:meth:`.begin` block as long as it doesn't enter "partial rollback"
2065
:meth:`.Session.begin` block in this mode, and will be ``True``
2066
within the :meth:`.Session.begin` block as long as it doesn't enter
2067
"partial rollback" state.
1956
2069
From all the above, it follows that the only purpose to this flag is
1957
2070
for application frameworks that wish to detect is a "rollback" is
1958
necessary within a generic error handling routine, for :class:`.Session`
1959
objects that would otherwise be in "partial rollback" mode. In
1960
a typical integration case, this is also not necessary as it is standard
1961
practice to emit :meth:`.Session.rollback` unconditionally within the
1962
outermost exception catch.
2071
necessary within a generic error handling routine, for
2072
:class:`.Session` objects that would otherwise be in
2073
"partial rollback" mode. In a typical integration case, this is also
2074
not necessary as it is standard practice to emit
2075
:meth:`.Session.rollback` unconditionally within the outermost
1964
2078
To track the transactional state of a :class:`.Session` fully,
1965
2079
use event listeners, primarily the :meth:`.SessionEvents.after_begin`,
1966
:meth:`.SessionEvents.after_commit`, :meth:`.SessionEvents.after_rollback`
2080
:meth:`.SessionEvents.after_commit`,
2081
:meth:`.SessionEvents.after_rollback` and related events.
1970
2084
return self.transaction and self.transaction.is_active
2034
2148
return util.IdentitySet(self._new.values())
2151
class sessionmaker(_SessionClassMethods):
2152
"""A configurable :class:`.Session` factory.
2154
The :class:`.sessionmaker` factory generates new
2155
:class:`.Session` objects when called, creating them given
2156
the configurational arguments established here.
2161
Session = sessionmaker(autoflush=False)
2163
# later, in a local scope, create and use a session:
2166
Any keyword arguments sent to the constructor itself will override the
2167
"configured" keywords::
2169
Session = sessionmaker()
2171
# bind an individual session to a connection
2172
sess = Session(bind=connection)
2174
The class also includes a method :meth:`.configure`, which can
2175
be used to specify additional keyword arguments to the factory, which
2176
will take effect for subsequent :class:`.Session` objects generated.
2177
This is usually used to associate one or more :class:`.Engine` objects
2178
with an existing :class:`.sessionmaker` factory before it is first
2181
# application starts
2182
Session = sessionmaker()
2185
engine = create_engine('sqlite:///foo.db')
2186
Session.configure(bind=engine)
2192
:ref:`session_getting` - introductory text on creating
2193
sessions using :class:`.sessionmaker`.
2197
def __init__(self, bind=None, class_=Session, autoflush=True,
2199
expire_on_commit=True, **kw):
2200
"""Construct a new :class:`.sessionmaker`.
2202
All arguments here except for ``class_`` correspond to arguments
2203
accepted by :class:`.Session` directly. See the
2204
:meth:`.Session.__init__` docstring for more details on parameters.
2206
:param bind: a :class:`.Engine` or other :class:`.Connectable` with
2207
which newly created :class:`.Session` objects will be associated.
2208
:param class_: class to use in order to create new :class:`.Session`
2209
objects. Defaults to :class:`.Session`.
2210
:param autoflush: The autoflush setting to use with newly created
2211
:class:`.Session` objects.
2212
:param autocommit: The autocommit setting to use with newly created
2213
:class:`.Session` objects.
2214
:param expire_on_commit=True: the expire_on_commit setting to use
2215
with newly created :class:`.Session` objects.
2216
:param \**kw: all other keyword arguments are passed to the constructor
2217
of newly created :class:`.Session` objects.
2221
kw['autoflush'] = autoflush
2222
kw['autocommit'] = autocommit
2223
kw['expire_on_commit'] = expire_on_commit
2225
# make our own subclass of the given class, so that
2226
# events can be associated with it specifically.
2227
self.class_ = type(class_.__name__, (class_,), {})
2229
def __call__(self, **local_kw):
2230
"""Produce a new :class:`.Session` object using the configuration
2231
established in this :class:`.sessionmaker`.
2233
In Python, the ``__call__`` method is invoked on an object when
2234
it is "called" in the same way as a function::
2236
Session = sessionmaker()
2237
session = Session() # invokes sessionmaker.__call__()
2240
for k, v in self.kw.items():
2241
local_kw.setdefault(k, v)
2242
return self.class_(**local_kw)
2244
def configure(self, **new_kw):
2245
"""(Re)configure the arguments for this sessionmaker.
2249
Session = sessionmaker()
2251
Session.configure(bind=create_engine('sqlite://'))
2253
self.kw.update(new_kw)
2256
return "%s(class_=%r%s)" % (
2257
self.__class__.__name__,
2258
self.class_.__name__,
2259
", ".join("%s=%r" % (k, v) for k, v in self.kw.items())
2036
2262
_sessions = weakref.WeakValueDictionary()
2038
2265
def make_transient(instance):
2039
2266
"""Make the given instance 'transient'.