| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162 |
- # orm/scoping.py
- # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
- # <see AUTHORS file>
- #
- # This module is part of SQLAlchemy and is released under
- # the MIT License: https://www.opensource.org/licenses/mit-license.php
- from __future__ import annotations
- from typing import Any
- from typing import Callable
- from typing import Dict
- from typing import Generic
- from typing import Iterable
- from typing import Iterator
- from typing import Optional
- from typing import overload
- from typing import Sequence
- from typing import Tuple
- from typing import Type
- from typing import TYPE_CHECKING
- from typing import TypeVar
- from typing import Union
- from .session import _S
- from .session import Session
- from .. import exc as sa_exc
- from .. import util
- from ..util import create_proxy_methods
- from ..util import ScopedRegistry
- from ..util import ThreadLocalRegistry
- from ..util import warn
- from ..util import warn_deprecated
- from ..util.typing import Protocol
- if TYPE_CHECKING:
- from ._typing import _EntityType
- from ._typing import _IdentityKeyType
- from ._typing import OrmExecuteOptionsParameter
- from .identity import IdentityMap
- from .interfaces import ORMOption
- from .mapper import Mapper
- from .query import Query
- from .query import RowReturningQuery
- from .session import _BindArguments
- from .session import _EntityBindKey
- from .session import _PKIdentityArgument
- from .session import _SessionBind
- from .session import sessionmaker
- from .session import SessionTransaction
- from ..engine import Connection
- from ..engine import CursorResult
- from ..engine import Engine
- from ..engine import Result
- from ..engine import Row
- from ..engine import RowMapping
- from ..engine.interfaces import _CoreAnyExecuteParams
- from ..engine.interfaces import _CoreSingleExecuteParams
- from ..engine.interfaces import CoreExecuteOptionsParameter
- from ..engine.result import ScalarResult
- from ..sql._typing import _ColumnsClauseArgument
- from ..sql._typing import _T0
- from ..sql._typing import _T1
- from ..sql._typing import _T2
- from ..sql._typing import _T3
- from ..sql._typing import _T4
- from ..sql._typing import _T5
- from ..sql._typing import _T6
- from ..sql._typing import _T7
- from ..sql._typing import _TypedColumnClauseArgument as _TCCA
- from ..sql.base import Executable
- from ..sql.dml import UpdateBase
- from ..sql.elements import ClauseElement
- from ..sql.roles import TypedColumnsClauseRole
- from ..sql.selectable import ForUpdateParameter
- from ..sql.selectable import TypedReturnsRows
- _T = TypeVar("_T", bound=Any)
- class QueryPropertyDescriptor(Protocol):
- """Describes the type applied to a class-level
- :meth:`_orm.scoped_session.query_property` attribute.
- .. versionadded:: 2.0.5
- """
- def __get__(self, instance: Any, owner: Type[_T]) -> Query[_T]: ...
- _O = TypeVar("_O", bound=object)
- __all__ = ["scoped_session"]
- @create_proxy_methods(
- Session,
- ":class:`_orm.Session`",
- ":class:`_orm.scoping.scoped_session`",
- classmethods=["close_all", "object_session", "identity_key"],
- methods=[
- "__contains__",
- "__iter__",
- "add",
- "add_all",
- "begin",
- "begin_nested",
- "close",
- "reset",
- "commit",
- "connection",
- "delete",
- "execute",
- "expire",
- "expire_all",
- "expunge",
- "expunge_all",
- "flush",
- "get",
- "get_one",
- "get_bind",
- "is_modified",
- "bulk_save_objects",
- "bulk_insert_mappings",
- "bulk_update_mappings",
- "merge",
- "query",
- "refresh",
- "rollback",
- "scalar",
- "scalars",
- ],
- attributes=[
- "bind",
- "dirty",
- "deleted",
- "new",
- "identity_map",
- "is_active",
- "autoflush",
- "no_autoflush",
- "info",
- ],
- )
- class scoped_session(Generic[_S]):
- """Provides scoped management of :class:`.Session` objects.
- See :ref:`unitofwork_contextual` for a tutorial.
- .. note::
- When using :ref:`asyncio_toplevel`, the async-compatible
- :class:`_asyncio.async_scoped_session` class should be
- used in place of :class:`.scoped_session`.
- """
- _support_async: bool = False
- session_factory: sessionmaker[_S]
- """The `session_factory` provided to `__init__` is stored in this
- attribute and may be accessed at a later time. This can be useful when
- a new non-scoped :class:`.Session` is needed."""
- registry: ScopedRegistry[_S]
- def __init__(
- self,
- session_factory: sessionmaker[_S],
- scopefunc: Optional[Callable[[], Any]] = None,
- ):
- """Construct a new :class:`.scoped_session`.
- :param session_factory: a factory to create new :class:`.Session`
- instances. This is usually, but not necessarily, an instance
- of :class:`.sessionmaker`.
- :param scopefunc: optional function which defines
- the current scope. If not passed, the :class:`.scoped_session`
- object assumes "thread-local" scope, and will use
- a Python ``threading.local()`` in order to maintain the current
- :class:`.Session`. If passed, the function should return
- a hashable token; this token will be used as the key in a
- dictionary in order to store and retrieve the current
- :class:`.Session`.
- """
- self.session_factory = session_factory
- if scopefunc:
- self.registry = ScopedRegistry(session_factory, scopefunc)
- else:
- self.registry = ThreadLocalRegistry(session_factory)
- @property
- def _proxied(self) -> _S:
- return self.registry()
- def __call__(self, **kw: Any) -> _S:
- r"""Return the current :class:`.Session`, creating it
- using the :attr:`.scoped_session.session_factory` if not present.
- :param \**kw: Keyword arguments will be passed to the
- :attr:`.scoped_session.session_factory` callable, if an existing
- :class:`.Session` is not present. If the :class:`.Session` is present
- and keyword arguments have been passed,
- :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
- """
- if kw:
- if self.registry.has():
- raise sa_exc.InvalidRequestError(
- "Scoped session is already present; "
- "no new arguments may be specified."
- )
- else:
- sess = self.session_factory(**kw)
- self.registry.set(sess)
- else:
- sess = self.registry()
- if not self._support_async and sess._is_asyncio:
- warn_deprecated(
- "Using `scoped_session` with asyncio is deprecated and "
- "will raise an error in a future version. "
- "Please use `async_scoped_session` instead.",
- "1.4.23",
- )
- return sess
- def configure(self, **kwargs: Any) -> None:
- """reconfigure the :class:`.sessionmaker` used by this
- :class:`.scoped_session`.
- See :meth:`.sessionmaker.configure`.
- """
- if self.registry.has():
- warn(
- "At least one scoped session is already present. "
- " configure() can not affect sessions that have "
- "already been created."
- )
- self.session_factory.configure(**kwargs)
- def remove(self) -> None:
- """Dispose of the current :class:`.Session`, if present.
- This will first call :meth:`.Session.close` method
- on the current :class:`.Session`, which releases any existing
- transactional/connection resources still being held; transactions
- specifically are rolled back. The :class:`.Session` is then
- discarded. Upon next usage within the same scope,
- the :class:`.scoped_session` will produce a new
- :class:`.Session` object.
- """
- if self.registry.has():
- self.registry().close()
- self.registry.clear()
- def query_property(
- self, query_cls: Optional[Type[Query[_T]]] = None
- ) -> QueryPropertyDescriptor:
- """return a class property which produces a legacy
- :class:`_query.Query` object against the class and the current
- :class:`.Session` when called.
- .. legacy:: The :meth:`_orm.scoped_session.query_property` accessor
- is specific to the legacy :class:`.Query` object and is not
- considered to be part of :term:`2.0-style` ORM use.
- e.g.::
- from sqlalchemy.orm import QueryPropertyDescriptor
- from sqlalchemy.orm import scoped_session
- from sqlalchemy.orm import sessionmaker
- Session = scoped_session(sessionmaker())
- class MyClass:
- query: QueryPropertyDescriptor = Session.query_property()
- # after mappers are defined
- result = MyClass.query.filter(MyClass.name == "foo").all()
- Produces instances of the session's configured query class by
- default. To override and use a custom implementation, provide
- a ``query_cls`` callable. The callable will be invoked with
- the class's mapper as a positional argument and a session
- keyword argument.
- There is no limit to the number of query properties placed on
- a class.
- """
- class query:
- def __get__(s, instance: Any, owner: Type[_O]) -> Query[_O]:
- if query_cls:
- # custom query class
- return query_cls(owner, session=self.registry()) # type: ignore # noqa: E501
- else:
- # session's configured query class
- return self.registry().query(owner)
- return query()
- # START PROXY METHODS scoped_session
- # code within this block is **programmatically,
- # statically generated** by tools/generate_proxy_methods.py
- def __contains__(self, instance: object) -> bool:
- r"""Return True if the instance is associated with this session.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- The instance may be pending or persistent within the Session for a
- result of True.
- """ # noqa: E501
- return self._proxied.__contains__(instance)
- def __iter__(self) -> Iterator[object]:
- r"""Iterate over all pending or persistent instances within this
- Session.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- """ # noqa: E501
- return self._proxied.__iter__()
- def add(self, instance: object, _warn: bool = True) -> None:
- r"""Place an object into this :class:`_orm.Session`.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Objects that are in the :term:`transient` state when passed to the
- :meth:`_orm.Session.add` method will move to the
- :term:`pending` state, until the next flush, at which point they
- will move to the :term:`persistent` state.
- Objects that are in the :term:`detached` state when passed to the
- :meth:`_orm.Session.add` method will move to the :term:`persistent`
- state directly.
- If the transaction used by the :class:`_orm.Session` is rolled back,
- objects which were transient when they were passed to
- :meth:`_orm.Session.add` will be moved back to the
- :term:`transient` state, and will no longer be present within this
- :class:`_orm.Session`.
- .. seealso::
- :meth:`_orm.Session.add_all`
- :ref:`session_adding` - at :ref:`session_basics`
- """ # noqa: E501
- return self._proxied.add(instance, _warn=_warn)
- def add_all(self, instances: Iterable[object]) -> None:
- r"""Add the given collection of instances to this :class:`_orm.Session`.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- See the documentation for :meth:`_orm.Session.add` for a general
- behavioral description.
- .. seealso::
- :meth:`_orm.Session.add`
- :ref:`session_adding` - at :ref:`session_basics`
- """ # noqa: E501
- return self._proxied.add_all(instances)
- def begin(self, nested: bool = False) -> SessionTransaction:
- r"""Begin a transaction, or nested transaction,
- on this :class:`.Session`, if one is not already begun.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- The :class:`_orm.Session` object features **autobegin** behavior,
- so that normally it is not necessary to call the
- :meth:`_orm.Session.begin`
- method explicitly. However, it may be used in order to control
- the scope of when the transactional state is begun.
- When used to begin the outermost transaction, an error is raised
- if this :class:`.Session` is already inside of a transaction.
- :param nested: if True, begins a SAVEPOINT transaction and is
- equivalent to calling :meth:`~.Session.begin_nested`. For
- documentation on SAVEPOINT transactions, please see
- :ref:`session_begin_nested`.
- :return: the :class:`.SessionTransaction` object. Note that
- :class:`.SessionTransaction`
- acts as a Python context manager, allowing :meth:`.Session.begin`
- to be used in a "with" block. See :ref:`session_explicit_begin` for
- an example.
- .. seealso::
- :ref:`session_autobegin`
- :ref:`unitofwork_transaction`
- :meth:`.Session.begin_nested`
- """ # noqa: E501
- return self._proxied.begin(nested=nested)
- def begin_nested(self) -> SessionTransaction:
- r"""Begin a "nested" transaction on this Session, e.g. SAVEPOINT.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- The target database(s) and associated drivers must support SQL
- SAVEPOINT for this method to function correctly.
- For documentation on SAVEPOINT
- transactions, please see :ref:`session_begin_nested`.
- :return: the :class:`.SessionTransaction` object. Note that
- :class:`.SessionTransaction` acts as a context manager, allowing
- :meth:`.Session.begin_nested` to be used in a "with" block.
- See :ref:`session_begin_nested` for a usage example.
- .. seealso::
- :ref:`session_begin_nested`
- :ref:`pysqlite_serializable` - special workarounds required
- with the SQLite driver in order for SAVEPOINT to work
- correctly. For asyncio use cases, see the section
- :ref:`aiosqlite_serializable`.
- """ # noqa: E501
- return self._proxied.begin_nested()
- def close(self) -> None:
- r"""Close out the transactional resources and ORM objects used by this
- :class:`_orm.Session`.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- This expunges all ORM objects associated with this
- :class:`_orm.Session`, ends any transaction in progress and
- :term:`releases` any :class:`_engine.Connection` objects which this
- :class:`_orm.Session` itself has checked out from associated
- :class:`_engine.Engine` objects. The operation then leaves the
- :class:`_orm.Session` in a state which it may be used again.
- .. tip::
- In the default running mode the :meth:`_orm.Session.close`
- method **does not prevent the Session from being used again**.
- The :class:`_orm.Session` itself does not actually have a
- distinct "closed" state; it merely means
- the :class:`_orm.Session` will release all database connections
- and ORM objects.
- Setting the parameter :paramref:`_orm.Session.close_resets_only`
- to ``False`` will instead make the ``close`` final, meaning that
- any further action on the session will be forbidden.
- .. versionchanged:: 1.4 The :meth:`.Session.close` method does not
- immediately create a new :class:`.SessionTransaction` object;
- instead, the new :class:`.SessionTransaction` is created only if
- the :class:`.Session` is used again for a database operation.
- .. seealso::
- :ref:`session_closing` - detail on the semantics of
- :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`.
- :meth:`_orm.Session.reset` - a similar method that behaves like
- ``close()`` with the parameter
- :paramref:`_orm.Session.close_resets_only` set to ``True``.
- """ # noqa: E501
- return self._proxied.close()
- def reset(self) -> None:
- r"""Close out the transactional resources and ORM objects used by this
- :class:`_orm.Session`, resetting the session to its initial state.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- This method provides for same "reset-only" behavior that the
- :meth:`_orm.Session.close` method has provided historically, where the
- state of the :class:`_orm.Session` is reset as though the object were
- brand new, and ready to be used again.
- This method may then be useful for :class:`_orm.Session` objects
- which set :paramref:`_orm.Session.close_resets_only` to ``False``,
- so that "reset only" behavior is still available.
- .. versionadded:: 2.0.22
- .. seealso::
- :ref:`session_closing` - detail on the semantics of
- :meth:`_orm.Session.close` and :meth:`_orm.Session.reset`.
- :meth:`_orm.Session.close` - a similar method will additionally
- prevent re-use of the Session when the parameter
- :paramref:`_orm.Session.close_resets_only` is set to ``False``.
- """ # noqa: E501
- return self._proxied.reset()
- def commit(self) -> None:
- r"""Flush pending changes and commit the current transaction.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- When the COMMIT operation is complete, all objects are fully
- :term:`expired`, erasing their internal contents, which will be
- automatically re-loaded when the objects are next accessed. In the
- interim, these objects are in an expired state and will not function if
- they are :term:`detached` from the :class:`.Session`. Additionally,
- this re-load operation is not supported when using asyncio-oriented
- APIs. The :paramref:`.Session.expire_on_commit` parameter may be used
- to disable this behavior.
- When there is no transaction in place for the :class:`.Session`,
- indicating that no operations were invoked on this :class:`.Session`
- since the previous call to :meth:`.Session.commit`, the method will
- begin and commit an internal-only "logical" transaction, that does not
- normally affect the database unless pending flush changes were
- detected, but will still invoke event handlers and object expiration
- rules.
- The outermost database transaction is committed unconditionally,
- automatically releasing any SAVEPOINTs in effect.
- .. seealso::
- :ref:`session_committing`
- :ref:`unitofwork_transaction`
- :ref:`asyncio_orm_avoid_lazyloads`
- """ # noqa: E501
- return self._proxied.commit()
- def connection(
- self,
- bind_arguments: Optional[_BindArguments] = None,
- execution_options: Optional[CoreExecuteOptionsParameter] = None,
- ) -> Connection:
- r"""Return a :class:`_engine.Connection` object corresponding to this
- :class:`.Session` object's transactional state.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Either the :class:`_engine.Connection` corresponding to the current
- transaction is returned, or if no transaction is in progress, a new
- one is begun and the :class:`_engine.Connection`
- returned (note that no
- transactional state is established with the DBAPI until the first
- SQL statement is emitted).
- Ambiguity in multi-bind or unbound :class:`.Session` objects can be
- resolved through any of the optional keyword arguments. This
- ultimately makes usage of the :meth:`.get_bind` method for resolution.
- :param bind_arguments: dictionary of bind arguments. May include
- "mapper", "bind", "clause", other custom arguments that are passed
- to :meth:`.Session.get_bind`.
- :param execution_options: a dictionary of execution options that will
- be passed to :meth:`_engine.Connection.execution_options`, **when the
- connection is first procured only**. If the connection is already
- present within the :class:`.Session`, a warning is emitted and
- the arguments are ignored.
- .. seealso::
- :ref:`session_transaction_isolation`
- """ # noqa: E501
- return self._proxied.connection(
- bind_arguments=bind_arguments, execution_options=execution_options
- )
- def delete(self, instance: object) -> None:
- r"""Mark an instance as deleted.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- The object is assumed to be either :term:`persistent` or
- :term:`detached` when passed; after the method is called, the
- object will remain in the :term:`persistent` state until the next
- flush proceeds. During this time, the object will also be a member
- of the :attr:`_orm.Session.deleted` collection.
- When the next flush proceeds, the object will move to the
- :term:`deleted` state, indicating a ``DELETE`` statement was emitted
- for its row within the current transaction. When the transaction
- is successfully committed,
- the deleted object is moved to the :term:`detached` state and is
- no longer present within this :class:`_orm.Session`.
- .. seealso::
- :ref:`session_deleting` - at :ref:`session_basics`
- """ # noqa: E501
- return self._proxied.delete(instance)
- @overload
- def execute(
- self,
- statement: TypedReturnsRows[_T],
- params: Optional[_CoreAnyExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- _parent_execute_state: Optional[Any] = None,
- _add_event: Optional[Any] = None,
- ) -> Result[_T]: ...
- @overload
- def execute(
- self,
- statement: UpdateBase,
- params: Optional[_CoreAnyExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- _parent_execute_state: Optional[Any] = None,
- _add_event: Optional[Any] = None,
- ) -> CursorResult[Any]: ...
- @overload
- def execute(
- self,
- statement: Executable,
- params: Optional[_CoreAnyExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- _parent_execute_state: Optional[Any] = None,
- _add_event: Optional[Any] = None,
- ) -> Result[Any]: ...
- def execute(
- self,
- statement: Executable,
- params: Optional[_CoreAnyExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- _parent_execute_state: Optional[Any] = None,
- _add_event: Optional[Any] = None,
- ) -> Result[Any]:
- r"""Execute a SQL expression construct.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Returns a :class:`_engine.Result` object representing
- results of the statement execution.
- E.g.::
- from sqlalchemy import select
- result = session.execute(select(User).where(User.id == 5))
- The API contract of :meth:`_orm.Session.execute` is similar to that
- of :meth:`_engine.Connection.execute`, the :term:`2.0 style` version
- of :class:`_engine.Connection`.
- .. versionchanged:: 1.4 the :meth:`_orm.Session.execute` method is
- now the primary point of ORM statement execution when using
- :term:`2.0 style` ORM usage.
- :param statement:
- An executable statement (i.e. an :class:`.Executable` expression
- such as :func:`_expression.select`).
- :param params:
- Optional dictionary, or list of dictionaries, containing
- bound parameter values. If a single dictionary, single-row
- execution occurs; if a list of dictionaries, an
- "executemany" will be invoked. The keys in each dictionary
- must correspond to parameter names present in the statement.
- :param execution_options: optional dictionary of execution options,
- which will be associated with the statement execution. This
- dictionary can provide a subset of the options that are accepted
- by :meth:`_engine.Connection.execution_options`, and may also
- provide additional options understood only in an ORM context.
- .. seealso::
- :ref:`orm_queryguide_execution_options` - ORM-specific execution
- options
- :param bind_arguments: dictionary of additional arguments to determine
- the bind. May include "mapper", "bind", or other custom arguments.
- Contents of this dictionary are passed to the
- :meth:`.Session.get_bind` method.
- :return: a :class:`_engine.Result` object.
- """ # noqa: E501
- return self._proxied.execute(
- statement,
- params=params,
- execution_options=execution_options,
- bind_arguments=bind_arguments,
- _parent_execute_state=_parent_execute_state,
- _add_event=_add_event,
- )
- def expire(
- self, instance: object, attribute_names: Optional[Iterable[str]] = None
- ) -> None:
- r"""Expire the attributes on an instance.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Marks the attributes of an instance as out of date. When an expired
- attribute is next accessed, a query will be issued to the
- :class:`.Session` object's current transactional context in order to
- load all expired attributes for the given instance. Note that
- a highly isolated transaction will return the same values as were
- previously read in that same transaction, regardless of changes
- in database state outside of that transaction.
- To expire all objects in the :class:`.Session` simultaneously,
- use :meth:`Session.expire_all`.
- The :class:`.Session` object's default behavior is to
- expire all state whenever the :meth:`Session.rollback`
- or :meth:`Session.commit` methods are called, so that new
- state can be loaded for the new transaction. For this reason,
- calling :meth:`Session.expire` only makes sense for the specific
- case that a non-ORM SQL statement was emitted in the current
- transaction.
- :param instance: The instance to be refreshed.
- :param attribute_names: optional list of string attribute names
- indicating a subset of attributes to be expired.
- .. seealso::
- :ref:`session_expire` - introductory material
- :meth:`.Session.expire`
- :meth:`.Session.refresh`
- :meth:`_orm.Query.populate_existing`
- """ # noqa: E501
- return self._proxied.expire(instance, attribute_names=attribute_names)
- def expire_all(self) -> None:
- r"""Expires all persistent instances within this Session.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- When any attributes on a persistent instance is next accessed,
- a query will be issued using the
- :class:`.Session` object's current transactional context in order to
- load all expired attributes for the given instance. Note that
- a highly isolated transaction will return the same values as were
- previously read in that same transaction, regardless of changes
- in database state outside of that transaction.
- To expire individual objects and individual attributes
- on those objects, use :meth:`Session.expire`.
- The :class:`.Session` object's default behavior is to
- expire all state whenever the :meth:`Session.rollback`
- or :meth:`Session.commit` methods are called, so that new
- state can be loaded for the new transaction. For this reason,
- calling :meth:`Session.expire_all` is not usually needed,
- assuming the transaction is isolated.
- .. seealso::
- :ref:`session_expire` - introductory material
- :meth:`.Session.expire`
- :meth:`.Session.refresh`
- :meth:`_orm.Query.populate_existing`
- """ # noqa: E501
- return self._proxied.expire_all()
- def expunge(self, instance: object) -> None:
- r"""Remove the `instance` from this ``Session``.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- This will free all internal references to the instance. Cascading
- will be applied according to the *expunge* cascade rule.
- """ # noqa: E501
- return self._proxied.expunge(instance)
- def expunge_all(self) -> None:
- r"""Remove all object instances from this ``Session``.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- This is equivalent to calling ``expunge(obj)`` on all objects in this
- ``Session``.
- """ # noqa: E501
- return self._proxied.expunge_all()
- def flush(self, objects: Optional[Sequence[Any]] = None) -> None:
- r"""Flush all the object changes to the database.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Writes out all pending object creations, deletions and modifications
- to the database as INSERTs, DELETEs, UPDATEs, etc. Operations are
- automatically ordered by the Session's unit of work dependency
- solver.
- Database operations will be issued in the current transactional
- context and do not affect the state of the transaction, unless an
- error occurs, in which case the entire transaction is rolled back.
- You may flush() as often as you like within a transaction to move
- changes from Python to the database's transaction buffer.
- :param objects: Optional; restricts the flush operation to operate
- only on elements that are in the given collection.
- This feature is for an extremely narrow set of use cases where
- particular objects may need to be operated upon before the
- full flush() occurs. It is not intended for general use.
- """ # noqa: E501
- return self._proxied.flush(objects=objects)
- def get(
- self,
- entity: _EntityBindKey[_O],
- ident: _PKIdentityArgument,
- *,
- options: Optional[Sequence[ORMOption]] = None,
- populate_existing: bool = False,
- with_for_update: ForUpdateParameter = None,
- identity_token: Optional[Any] = None,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- ) -> Optional[_O]:
- r"""Return an instance based on the given primary key identifier,
- or ``None`` if not found.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- E.g.::
- my_user = session.get(User, 5)
- some_object = session.get(VersionedFoo, (5, 10))
- some_object = session.get(VersionedFoo, {"id": 5, "version_id": 10})
- .. versionadded:: 1.4 Added :meth:`_orm.Session.get`, which is moved
- from the now legacy :meth:`_orm.Query.get` method.
- :meth:`_orm.Session.get` is special in that it provides direct
- access to the identity map of the :class:`.Session`.
- If the given primary key identifier is present
- in the local identity map, the object is returned
- directly from this collection and no SQL is emitted,
- unless the object has been marked fully expired.
- If not present,
- a SELECT is performed in order to locate the object.
- :meth:`_orm.Session.get` also will perform a check if
- the object is present in the identity map and
- marked as expired - a SELECT
- is emitted to refresh the object as well as to
- ensure that the row is still present.
- If not, :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised.
- :param entity: a mapped class or :class:`.Mapper` indicating the
- type of entity to be loaded.
- :param ident: A scalar, tuple, or dictionary representing the
- primary key. For a composite (e.g. multiple column) primary key,
- a tuple or dictionary should be passed.
- For a single-column primary key, the scalar calling form is typically
- the most expedient. If the primary key of a row is the value "5",
- the call looks like::
- my_object = session.get(SomeClass, 5)
- The tuple form contains primary key values typically in
- the order in which they correspond to the mapped
- :class:`_schema.Table`
- object's primary key columns, or if the
- :paramref:`_orm.Mapper.primary_key` configuration parameter were
- used, in
- the order used for that parameter. For example, if the primary key
- of a row is represented by the integer
- digits "5, 10" the call would look like::
- my_object = session.get(SomeClass, (5, 10))
- The dictionary form should include as keys the mapped attribute names
- corresponding to each element of the primary key. If the mapped class
- has the attributes ``id``, ``version_id`` as the attributes which
- store the object's primary key value, the call would look like::
- my_object = session.get(SomeClass, {"id": 5, "version_id": 10})
- :param options: optional sequence of loader options which will be
- applied to the query, if one is emitted.
- :param populate_existing: causes the method to unconditionally emit
- a SQL query and refresh the object with the newly loaded data,
- regardless of whether or not the object is already present.
- :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
- should be used, or may be a dictionary containing flags to
- indicate a more specific set of FOR UPDATE flags for the SELECT;
- flags should match the parameters of
- :meth:`_query.Query.with_for_update`.
- Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
- :param execution_options: optional dictionary of execution options,
- which will be associated with the query execution if one is emitted.
- This dictionary can provide a subset of the options that are
- accepted by :meth:`_engine.Connection.execution_options`, and may
- also provide additional options understood only in an ORM context.
- .. versionadded:: 1.4.29
- .. seealso::
- :ref:`orm_queryguide_execution_options` - ORM-specific execution
- options
- :param bind_arguments: dictionary of additional arguments to determine
- the bind. May include "mapper", "bind", or other custom arguments.
- Contents of this dictionary are passed to the
- :meth:`.Session.get_bind` method.
- .. versionadded: 2.0.0rc1
- :return: The object instance, or ``None``.
- """ # noqa: E501
- return self._proxied.get(
- entity,
- ident,
- options=options,
- populate_existing=populate_existing,
- with_for_update=with_for_update,
- identity_token=identity_token,
- execution_options=execution_options,
- bind_arguments=bind_arguments,
- )
- def get_one(
- self,
- entity: _EntityBindKey[_O],
- ident: _PKIdentityArgument,
- *,
- options: Optional[Sequence[ORMOption]] = None,
- populate_existing: bool = False,
- with_for_update: ForUpdateParameter = None,
- identity_token: Optional[Any] = None,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- ) -> _O:
- r"""Return exactly one instance based on the given primary key
- identifier, or raise an exception if not found.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Raises :class:`_exc.NoResultFound` if the query selects no rows.
- For a detailed documentation of the arguments see the
- method :meth:`.Session.get`.
- .. versionadded:: 2.0.22
- :return: The object instance.
- .. seealso::
- :meth:`.Session.get` - equivalent method that instead
- returns ``None`` if no row was found with the provided primary
- key
- """ # noqa: E501
- return self._proxied.get_one(
- entity,
- ident,
- options=options,
- populate_existing=populate_existing,
- with_for_update=with_for_update,
- identity_token=identity_token,
- execution_options=execution_options,
- bind_arguments=bind_arguments,
- )
- def get_bind(
- self,
- mapper: Optional[_EntityBindKey[_O]] = None,
- *,
- clause: Optional[ClauseElement] = None,
- bind: Optional[_SessionBind] = None,
- _sa_skip_events: Optional[bool] = None,
- _sa_skip_for_implicit_returning: bool = False,
- **kw: Any,
- ) -> Union[Engine, Connection]:
- r"""Return a "bind" to which this :class:`.Session` is bound.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- The "bind" is usually an instance of :class:`_engine.Engine`,
- except in the case where the :class:`.Session` has been
- explicitly bound directly to a :class:`_engine.Connection`.
- For a multiply-bound or unbound :class:`.Session`, the
- ``mapper`` or ``clause`` arguments are used to determine the
- appropriate bind to return.
- Note that the "mapper" argument is usually present
- when :meth:`.Session.get_bind` is called via an ORM
- operation such as a :meth:`.Session.query`, each
- individual INSERT/UPDATE/DELETE operation within a
- :meth:`.Session.flush`, call, etc.
- The order of resolution is:
- 1. if mapper given and :paramref:`.Session.binds` is present,
- locate a bind based first on the mapper in use, then
- on the mapped class in use, then on any base classes that are
- present in the ``__mro__`` of the mapped class, from more specific
- superclasses to more general.
- 2. if clause given and ``Session.binds`` is present,
- locate a bind based on :class:`_schema.Table` objects
- found in the given clause present in ``Session.binds``.
- 3. if ``Session.binds`` is present, return that.
- 4. if clause given, attempt to return a bind
- linked to the :class:`_schema.MetaData` ultimately
- associated with the clause.
- 5. if mapper given, attempt to return a bind
- linked to the :class:`_schema.MetaData` ultimately
- associated with the :class:`_schema.Table` or other
- selectable to which the mapper is mapped.
- 6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
- is raised.
- Note that the :meth:`.Session.get_bind` method can be overridden on
- a user-defined subclass of :class:`.Session` to provide any kind
- of bind resolution scheme. See the example at
- :ref:`session_custom_partitioning`.
- :param mapper:
- Optional mapped class or corresponding :class:`_orm.Mapper` instance.
- The bind can be derived from a :class:`_orm.Mapper` first by
- consulting the "binds" map associated with this :class:`.Session`,
- and secondly by consulting the :class:`_schema.MetaData` associated
- with the :class:`_schema.Table` to which the :class:`_orm.Mapper` is
- mapped for a bind.
- :param clause:
- A :class:`_expression.ClauseElement` (i.e.
- :func:`_expression.select`,
- :func:`_expression.text`,
- etc.). If the ``mapper`` argument is not present or could not
- produce a bind, the given expression construct will be searched
- for a bound element, typically a :class:`_schema.Table`
- associated with
- bound :class:`_schema.MetaData`.
- .. seealso::
- :ref:`session_partitioning`
- :paramref:`.Session.binds`
- :meth:`.Session.bind_mapper`
- :meth:`.Session.bind_table`
- """ # noqa: E501
- return self._proxied.get_bind(
- mapper=mapper,
- clause=clause,
- bind=bind,
- _sa_skip_events=_sa_skip_events,
- _sa_skip_for_implicit_returning=_sa_skip_for_implicit_returning,
- **kw,
- )
- def is_modified(
- self, instance: object, include_collections: bool = True
- ) -> bool:
- r"""Return ``True`` if the given instance has locally
- modified attributes.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- This method retrieves the history for each instrumented
- attribute on the instance and performs a comparison of the current
- value to its previously flushed or committed value, if any.
- It is in effect a more expensive and accurate
- version of checking for the given instance in the
- :attr:`.Session.dirty` collection; a full test for
- each attribute's net "dirty" status is performed.
- E.g.::
- return session.is_modified(someobject)
- A few caveats to this method apply:
- * Instances present in the :attr:`.Session.dirty` collection may
- report ``False`` when tested with this method. This is because
- the object may have received change events via attribute mutation,
- thus placing it in :attr:`.Session.dirty`, but ultimately the state
- is the same as that loaded from the database, resulting in no net
- change here.
- * Scalar attributes may not have recorded the previously set
- value when a new value was applied, if the attribute was not loaded,
- or was expired, at the time the new value was received - in these
- cases, the attribute is assumed to have a change, even if there is
- ultimately no net change against its database value. SQLAlchemy in
- most cases does not need the "old" value when a set event occurs, so
- it skips the expense of a SQL call if the old value isn't present,
- based on the assumption that an UPDATE of the scalar value is
- usually needed, and in those few cases where it isn't, is less
- expensive on average than issuing a defensive SELECT.
- The "old" value is fetched unconditionally upon set only if the
- attribute container has the ``active_history`` flag set to ``True``.
- This flag is set typically for primary key attributes and scalar
- object references that are not a simple many-to-one. To set this
- flag for any arbitrary mapped column, use the ``active_history``
- argument with :func:`.column_property`.
- :param instance: mapped instance to be tested for pending changes.
- :param include_collections: Indicates if multivalued collections
- should be included in the operation. Setting this to ``False`` is a
- way to detect only local-column based properties (i.e. scalar columns
- or many-to-one foreign keys) that would result in an UPDATE for this
- instance upon flush.
- """ # noqa: E501
- return self._proxied.is_modified(
- instance, include_collections=include_collections
- )
- def bulk_save_objects(
- self,
- objects: Iterable[object],
- return_defaults: bool = False,
- update_changed_only: bool = True,
- preserve_order: bool = True,
- ) -> None:
- r"""Perform a bulk save of the given list of objects.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- .. legacy::
- This method is a legacy feature as of the 2.0 series of
- SQLAlchemy. For modern bulk INSERT and UPDATE, see
- the sections :ref:`orm_queryguide_bulk_insert` and
- :ref:`orm_queryguide_bulk_update`.
- For general INSERT and UPDATE of existing ORM mapped objects,
- prefer standard :term:`unit of work` data management patterns,
- introduced in the :ref:`unified_tutorial` at
- :ref:`tutorial_orm_data_manipulation`. SQLAlchemy 2.0
- now uses :ref:`engine_insertmanyvalues` with modern dialects
- which solves previous issues of bulk INSERT slowness.
- :param objects: a sequence of mapped object instances. The mapped
- objects are persisted as is, and are **not** associated with the
- :class:`.Session` afterwards.
- For each object, whether the object is sent as an INSERT or an
- UPDATE is dependent on the same rules used by the :class:`.Session`
- in traditional operation; if the object has the
- :attr:`.InstanceState.key`
- attribute set, then the object is assumed to be "detached" and
- will result in an UPDATE. Otherwise, an INSERT is used.
- In the case of an UPDATE, statements are grouped based on which
- attributes have changed, and are thus to be the subject of each
- SET clause. If ``update_changed_only`` is False, then all
- attributes present within each object are applied to the UPDATE
- statement, which may help in allowing the statements to be grouped
- together into a larger executemany(), and will also reduce the
- overhead of checking history on attributes.
- :param return_defaults: when True, rows that are missing values which
- generate defaults, namely integer primary key defaults and sequences,
- will be inserted **one at a time**, so that the primary key value
- is available. In particular this will allow joined-inheritance
- and other multi-table mappings to insert correctly without the need
- to provide primary key values ahead of time; however,
- :paramref:`.Session.bulk_save_objects.return_defaults` **greatly
- reduces the performance gains** of the method overall. It is strongly
- advised to please use the standard :meth:`_orm.Session.add_all`
- approach.
- :param update_changed_only: when True, UPDATE statements are rendered
- based on those attributes in each state that have logged changes.
- When False, all attributes present are rendered into the SET clause
- with the exception of primary key attributes.
- :param preserve_order: when True, the order of inserts and updates
- matches exactly the order in which the objects are given. When
- False, common types of objects are grouped into inserts
- and updates, to allow for more batching opportunities.
- .. seealso::
- :doc:`queryguide/dml`
- :meth:`.Session.bulk_insert_mappings`
- :meth:`.Session.bulk_update_mappings`
- """ # noqa: E501
- return self._proxied.bulk_save_objects(
- objects,
- return_defaults=return_defaults,
- update_changed_only=update_changed_only,
- preserve_order=preserve_order,
- )
- def bulk_insert_mappings(
- self,
- mapper: Mapper[Any],
- mappings: Iterable[Dict[str, Any]],
- return_defaults: bool = False,
- render_nulls: bool = False,
- ) -> None:
- r"""Perform a bulk insert of the given list of mapping dictionaries.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- .. legacy::
- This method is a legacy feature as of the 2.0 series of
- SQLAlchemy. For modern bulk INSERT and UPDATE, see
- the sections :ref:`orm_queryguide_bulk_insert` and
- :ref:`orm_queryguide_bulk_update`. The 2.0 API shares
- implementation details with this method and adds new features
- as well.
- :param mapper: a mapped class, or the actual :class:`_orm.Mapper`
- object,
- representing the single kind of object represented within the mapping
- list.
- :param mappings: a sequence of dictionaries, each one containing the
- state of the mapped row to be inserted, in terms of the attribute
- names on the mapped class. If the mapping refers to multiple tables,
- such as a joined-inheritance mapping, each dictionary must contain all
- keys to be populated into all tables.
- :param return_defaults: when True, the INSERT process will be altered
- to ensure that newly generated primary key values will be fetched.
- The rationale for this parameter is typically to enable
- :ref:`Joined Table Inheritance <joined_inheritance>` mappings to
- be bulk inserted.
- .. note:: for backends that don't support RETURNING, the
- :paramref:`_orm.Session.bulk_insert_mappings.return_defaults`
- parameter can significantly decrease performance as INSERT
- statements can no longer be batched. See
- :ref:`engine_insertmanyvalues`
- for background on which backends are affected.
- :param render_nulls: When True, a value of ``None`` will result
- in a NULL value being included in the INSERT statement, rather
- than the column being omitted from the INSERT. This allows all
- the rows being INSERTed to have the identical set of columns which
- allows the full set of rows to be batched to the DBAPI. Normally,
- each column-set that contains a different combination of NULL values
- than the previous row must omit a different series of columns from
- the rendered INSERT statement, which means it must be emitted as a
- separate statement. By passing this flag, the full set of rows
- are guaranteed to be batchable into one batch; the cost however is
- that server-side defaults which are invoked by an omitted column will
- be skipped, so care must be taken to ensure that these are not
- necessary.
- .. warning::
- When this flag is set, **server side default SQL values will
- not be invoked** for those columns that are inserted as NULL;
- the NULL value will be sent explicitly. Care must be taken
- to ensure that no server-side default functions need to be
- invoked for the operation as a whole.
- .. seealso::
- :doc:`queryguide/dml`
- :meth:`.Session.bulk_save_objects`
- :meth:`.Session.bulk_update_mappings`
- """ # noqa: E501
- return self._proxied.bulk_insert_mappings(
- mapper,
- mappings,
- return_defaults=return_defaults,
- render_nulls=render_nulls,
- )
- def bulk_update_mappings(
- self, mapper: Mapper[Any], mappings: Iterable[Dict[str, Any]]
- ) -> None:
- r"""Perform a bulk update of the given list of mapping dictionaries.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- .. legacy::
- This method is a legacy feature as of the 2.0 series of
- SQLAlchemy. For modern bulk INSERT and UPDATE, see
- the sections :ref:`orm_queryguide_bulk_insert` and
- :ref:`orm_queryguide_bulk_update`. The 2.0 API shares
- implementation details with this method and adds new features
- as well.
- :param mapper: a mapped class, or the actual :class:`_orm.Mapper`
- object,
- representing the single kind of object represented within the mapping
- list.
- :param mappings: a sequence of dictionaries, each one containing the
- state of the mapped row to be updated, in terms of the attribute names
- on the mapped class. If the mapping refers to multiple tables, such
- as a joined-inheritance mapping, each dictionary may contain keys
- corresponding to all tables. All those keys which are present and
- are not part of the primary key are applied to the SET clause of the
- UPDATE statement; the primary key values, which are required, are
- applied to the WHERE clause.
- .. seealso::
- :doc:`queryguide/dml`
- :meth:`.Session.bulk_insert_mappings`
- :meth:`.Session.bulk_save_objects`
- """ # noqa: E501
- return self._proxied.bulk_update_mappings(mapper, mappings)
- def merge(
- self,
- instance: _O,
- *,
- load: bool = True,
- options: Optional[Sequence[ORMOption]] = None,
- ) -> _O:
- r"""Copy the state of a given instance into a corresponding instance
- within this :class:`.Session`.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- :meth:`.Session.merge` examines the primary key attributes of the
- source instance, and attempts to reconcile it with an instance of the
- same primary key in the session. If not found locally, it attempts
- to load the object from the database based on primary key, and if
- none can be located, creates a new instance. The state of each
- attribute on the source instance is then copied to the target
- instance. The resulting target instance is then returned by the
- method; the original source instance is left unmodified, and
- un-associated with the :class:`.Session` if not already.
- This operation cascades to associated instances if the association is
- mapped with ``cascade="merge"``.
- See :ref:`unitofwork_merging` for a detailed discussion of merging.
- :param instance: Instance to be merged.
- :param load: Boolean, when False, :meth:`.merge` switches into
- a "high performance" mode which causes it to forego emitting history
- events as well as all database access. This flag is used for
- cases such as transferring graphs of objects into a :class:`.Session`
- from a second level cache, or to transfer just-loaded objects
- into the :class:`.Session` owned by a worker thread or process
- without re-querying the database.
- The ``load=False`` use case adds the caveat that the given
- object has to be in a "clean" state, that is, has no pending changes
- to be flushed - even if the incoming object is detached from any
- :class:`.Session`. This is so that when
- the merge operation populates local attributes and
- cascades to related objects and
- collections, the values can be "stamped" onto the
- target object as is, without generating any history or attribute
- events, and without the need to reconcile the incoming data with
- any existing related objects or collections that might not
- be loaded. The resulting objects from ``load=False`` are always
- produced as "clean", so it is only appropriate that the given objects
- should be "clean" as well, else this suggests a mis-use of the
- method.
- :param options: optional sequence of loader options which will be
- applied to the :meth:`_orm.Session.get` method when the merge
- operation loads the existing version of the object from the database.
- .. versionadded:: 1.4.24
- .. seealso::
- :func:`.make_transient_to_detached` - provides for an alternative
- means of "merging" a single object into the :class:`.Session`
- """ # noqa: E501
- return self._proxied.merge(instance, load=load, options=options)
- @overload
- def query(self, _entity: _EntityType[_O]) -> Query[_O]: ...
- @overload
- def query(
- self, _colexpr: TypedColumnsClauseRole[_T]
- ) -> RowReturningQuery[Tuple[_T]]: ...
- # START OVERLOADED FUNCTIONS self.query RowReturningQuery 2-8
- # code within this block is **programmatically,
- # statically generated** by tools/generate_tuple_map_overloads.py
- @overload
- def query(
- self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1]
- ) -> RowReturningQuery[Tuple[_T0, _T1]]: ...
- @overload
- def query(
- self, __ent0: _TCCA[_T0], __ent1: _TCCA[_T1], __ent2: _TCCA[_T2]
- ) -> RowReturningQuery[Tuple[_T0, _T1, _T2]]: ...
- @overload
- def query(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3]]: ...
- @overload
- def query(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4]]: ...
- @overload
- def query(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- __ent5: _TCCA[_T5],
- ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5]]: ...
- @overload
- def query(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- __ent5: _TCCA[_T5],
- __ent6: _TCCA[_T6],
- ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6]]: ...
- @overload
- def query(
- self,
- __ent0: _TCCA[_T0],
- __ent1: _TCCA[_T1],
- __ent2: _TCCA[_T2],
- __ent3: _TCCA[_T3],
- __ent4: _TCCA[_T4],
- __ent5: _TCCA[_T5],
- __ent6: _TCCA[_T6],
- __ent7: _TCCA[_T7],
- ) -> RowReturningQuery[Tuple[_T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7]]: ...
- # END OVERLOADED FUNCTIONS self.query
- @overload
- def query(
- self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any
- ) -> Query[Any]: ...
- def query(
- self, *entities: _ColumnsClauseArgument[Any], **kwargs: Any
- ) -> Query[Any]:
- r"""Return a new :class:`_query.Query` object corresponding to this
- :class:`_orm.Session`.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Note that the :class:`_query.Query` object is legacy as of
- SQLAlchemy 2.0; the :func:`_sql.select` construct is now used
- to construct ORM queries.
- .. seealso::
- :ref:`unified_tutorial`
- :ref:`queryguide_toplevel`
- :ref:`query_api_toplevel` - legacy API doc
- """ # noqa: E501
- return self._proxied.query(*entities, **kwargs)
- def refresh(
- self,
- instance: object,
- attribute_names: Optional[Iterable[str]] = None,
- with_for_update: ForUpdateParameter = None,
- ) -> None:
- r"""Expire and refresh attributes on the given instance.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- The selected attributes will first be expired as they would when using
- :meth:`_orm.Session.expire`; then a SELECT statement will be issued to
- the database to refresh column-oriented attributes with the current
- value available in the current transaction.
- :func:`_orm.relationship` oriented attributes will also be immediately
- loaded if they were already eagerly loaded on the object, using the
- same eager loading strategy that they were loaded with originally.
- .. versionadded:: 1.4 - the :meth:`_orm.Session.refresh` method
- can also refresh eagerly loaded attributes.
- :func:`_orm.relationship` oriented attributes that would normally
- load using the ``select`` (or "lazy") loader strategy will also
- load **if they are named explicitly in the attribute_names
- collection**, emitting a SELECT statement for the attribute using the
- ``immediate`` loader strategy. If lazy-loaded relationships are not
- named in :paramref:`_orm.Session.refresh.attribute_names`, then
- they remain as "lazy loaded" attributes and are not implicitly
- refreshed.
- .. versionchanged:: 2.0.4 The :meth:`_orm.Session.refresh` method
- will now refresh lazy-loaded :func:`_orm.relationship` oriented
- attributes for those which are named explicitly in the
- :paramref:`_orm.Session.refresh.attribute_names` collection.
- .. tip::
- While the :meth:`_orm.Session.refresh` method is capable of
- refreshing both column and relationship oriented attributes, its
- primary focus is on refreshing of local column-oriented attributes
- on a single instance. For more open ended "refresh" functionality,
- including the ability to refresh the attributes on many objects at
- once while having explicit control over relationship loader
- strategies, use the
- :ref:`populate existing <orm_queryguide_populate_existing>` feature
- instead.
- Note that a highly isolated transaction will return the same values as
- were previously read in that same transaction, regardless of changes
- in database state outside of that transaction. Refreshing
- attributes usually only makes sense at the start of a transaction
- where database rows have not yet been accessed.
- :param attribute_names: optional. An iterable collection of
- string attribute names indicating a subset of attributes to
- be refreshed.
- :param with_for_update: optional boolean ``True`` indicating FOR UPDATE
- should be used, or may be a dictionary containing flags to
- indicate a more specific set of FOR UPDATE flags for the SELECT;
- flags should match the parameters of
- :meth:`_query.Query.with_for_update`.
- Supersedes the :paramref:`.Session.refresh.lockmode` parameter.
- .. seealso::
- :ref:`session_expire` - introductory material
- :meth:`.Session.expire`
- :meth:`.Session.expire_all`
- :ref:`orm_queryguide_populate_existing` - allows any ORM query
- to refresh objects as they would be loaded normally.
- """ # noqa: E501
- return self._proxied.refresh(
- instance,
- attribute_names=attribute_names,
- with_for_update=with_for_update,
- )
- def rollback(self) -> None:
- r"""Rollback the current transaction in progress.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- If no transaction is in progress, this method is a pass-through.
- The method always rolls back
- the topmost database transaction, discarding any nested
- transactions that may be in progress.
- .. seealso::
- :ref:`session_rollback`
- :ref:`unitofwork_transaction`
- """ # noqa: E501
- return self._proxied.rollback()
- @overload
- def scalar(
- self,
- statement: TypedReturnsRows[Tuple[_T]],
- params: Optional[_CoreSingleExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- **kw: Any,
- ) -> Optional[_T]: ...
- @overload
- def scalar(
- self,
- statement: Executable,
- params: Optional[_CoreSingleExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- **kw: Any,
- ) -> Any: ...
- def scalar(
- self,
- statement: Executable,
- params: Optional[_CoreSingleExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- **kw: Any,
- ) -> Any:
- r"""Execute a statement and return a scalar result.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Usage and parameters are the same as that of
- :meth:`_orm.Session.execute`; the return result is a scalar Python
- value.
- """ # noqa: E501
- return self._proxied.scalar(
- statement,
- params=params,
- execution_options=execution_options,
- bind_arguments=bind_arguments,
- **kw,
- )
- @overload
- def scalars(
- self,
- statement: TypedReturnsRows[Tuple[_T]],
- params: Optional[_CoreAnyExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- **kw: Any,
- ) -> ScalarResult[_T]: ...
- @overload
- def scalars(
- self,
- statement: Executable,
- params: Optional[_CoreAnyExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- **kw: Any,
- ) -> ScalarResult[Any]: ...
- def scalars(
- self,
- statement: Executable,
- params: Optional[_CoreAnyExecuteParams] = None,
- *,
- execution_options: OrmExecuteOptionsParameter = util.EMPTY_DICT,
- bind_arguments: Optional[_BindArguments] = None,
- **kw: Any,
- ) -> ScalarResult[Any]:
- r"""Execute a statement and return the results as scalars.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- Usage and parameters are the same as that of
- :meth:`_orm.Session.execute`; the return result is a
- :class:`_result.ScalarResult` filtering object which
- will return single elements rather than :class:`_row.Row` objects.
- :return: a :class:`_result.ScalarResult` object
- .. versionadded:: 1.4.24 Added :meth:`_orm.Session.scalars`
- .. versionadded:: 1.4.26 Added :meth:`_orm.scoped_session.scalars`
- .. seealso::
- :ref:`orm_queryguide_select_orm_entities` - contrasts the behavior
- of :meth:`_orm.Session.execute` to :meth:`_orm.Session.scalars`
- """ # noqa: E501
- return self._proxied.scalars(
- statement,
- params=params,
- execution_options=execution_options,
- bind_arguments=bind_arguments,
- **kw,
- )
- @property
- def bind(self) -> Optional[Union[Engine, Connection]]:
- r"""Proxy for the :attr:`_orm.Session.bind` attribute
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- """ # noqa: E501
- return self._proxied.bind
- @bind.setter
- def bind(self, attr: Optional[Union[Engine, Connection]]) -> None:
- self._proxied.bind = attr
- @property
- def dirty(self) -> Any:
- r"""The set of all persistent instances considered dirty.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- E.g.::
- some_mapped_object in session.dirty
- Instances are considered dirty when they were modified but not
- deleted.
- Note that this 'dirty' calculation is 'optimistic'; most
- attribute-setting or collection modification operations will
- mark an instance as 'dirty' and place it in this set, even if
- there is no net change to the attribute's value. At flush
- time, the value of each attribute is compared to its
- previously saved value, and if there's no net change, no SQL
- operation will occur (this is a more expensive operation so
- it's only done at flush time).
- To check if an instance has actionable net changes to its
- attributes, use the :meth:`.Session.is_modified` method.
- """ # noqa: E501
- return self._proxied.dirty
- @property
- def deleted(self) -> Any:
- r"""The set of all instances marked as 'deleted' within this ``Session``
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- """ # noqa: E501
- return self._proxied.deleted
- @property
- def new(self) -> Any:
- r"""The set of all instances marked as 'new' within this ``Session``.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- """ # noqa: E501
- return self._proxied.new
- @property
- def identity_map(self) -> IdentityMap:
- r"""Proxy for the :attr:`_orm.Session.identity_map` attribute
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- """ # noqa: E501
- return self._proxied.identity_map
- @identity_map.setter
- def identity_map(self, attr: IdentityMap) -> None:
- self._proxied.identity_map = attr
- @property
- def is_active(self) -> Any:
- r"""True if this :class:`.Session` not in "partial rollback" state.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- .. versionchanged:: 1.4 The :class:`_orm.Session` no longer begins
- a new transaction immediately, so this attribute will be False
- when the :class:`_orm.Session` is first instantiated.
- "partial rollback" state typically indicates that the flush process
- of the :class:`_orm.Session` has failed, and that the
- :meth:`_orm.Session.rollback` method must be emitted in order to
- fully roll back the transaction.
- If this :class:`_orm.Session` is not in a transaction at all, the
- :class:`_orm.Session` will autobegin when it is first used, so in this
- case :attr:`_orm.Session.is_active` will return True.
- Otherwise, if this :class:`_orm.Session` is within a transaction,
- and that transaction has not been rolled back internally, the
- :attr:`_orm.Session.is_active` will also return True.
- .. seealso::
- :ref:`faq_session_rollback`
- :meth:`_orm.Session.in_transaction`
- """ # noqa: E501
- return self._proxied.is_active
- @property
- def autoflush(self) -> bool:
- r"""Proxy for the :attr:`_orm.Session.autoflush` attribute
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- """ # noqa: E501
- return self._proxied.autoflush
- @autoflush.setter
- def autoflush(self, attr: bool) -> None:
- self._proxied.autoflush = attr
- @property
- def no_autoflush(self) -> Any:
- r"""Return a context manager that disables autoflush.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- e.g.::
- with session.no_autoflush:
- some_object = SomeClass()
- session.add(some_object)
- # won't autoflush
- some_object.related_thing = session.query(SomeRelated).first()
- Operations that proceed within the ``with:`` block
- will not be subject to flushes occurring upon query
- access. This is useful when initializing a series
- of objects which involve existing database queries,
- where the uncompleted object should not yet be flushed.
- """ # noqa: E501
- return self._proxied.no_autoflush
- @property
- def info(self) -> Any:
- r"""A user-modifiable dictionary.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class
- on behalf of the :class:`_orm.scoping.scoped_session` class.
- The initial value of this dictionary can be populated using the
- ``info`` argument to the :class:`.Session` constructor or
- :class:`.sessionmaker` constructor or factory methods. The dictionary
- here is always local to this :class:`.Session` and can be modified
- independently of all other :class:`.Session` objects.
- """ # noqa: E501
- return self._proxied.info
- @classmethod
- def close_all(cls) -> None:
- r"""Close *all* sessions in memory.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- .. deprecated:: 1.3 The :meth:`.Session.close_all` method is deprecated and will be removed in a future release. Please refer to :func:`.session.close_all_sessions`.
- """ # noqa: E501
- return Session.close_all()
- @classmethod
- def object_session(cls, instance: object) -> Optional[Session]:
- r"""Return the :class:`.Session` to which an object belongs.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- This is an alias of :func:`.object_session`.
- """ # noqa: E501
- return Session.object_session(instance)
- @classmethod
- def identity_key(
- cls,
- class_: Optional[Type[Any]] = None,
- ident: Union[Any, Tuple[Any, ...]] = None,
- *,
- instance: Optional[Any] = None,
- row: Optional[Union[Row[Any], RowMapping]] = None,
- identity_token: Optional[Any] = None,
- ) -> _IdentityKeyType[Any]:
- r"""Return an identity key.
- .. container:: class_bases
- Proxied for the :class:`_orm.Session` class on
- behalf of the :class:`_orm.scoping.scoped_session` class.
- This is an alias of :func:`.util.identity_key`.
- """ # noqa: E501
- return Session.identity_key(
- class_=class_,
- ident=ident,
- instance=instance,
- row=row,
- identity_token=identity_token,
- )
- # END PROXY METHODS scoped_session
- ScopedSession = scoped_session
- """Old name for backwards compatibility."""
|